mahis_emr_api_lab 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +71 -0
- data/Rakefile +32 -0
- data/app/controllers/lab/application_controller.rb +6 -0
- data/app/controllers/lab/labels_controller.rb +17 -0
- data/app/controllers/lab/orders_controller.rb +78 -0
- data/app/controllers/lab/reasons_for_test_controller.rb +9 -0
- data/app/controllers/lab/results_controller.rb +20 -0
- data/app/controllers/lab/specimen_types_controller.rb +15 -0
- data/app/controllers/lab/test_result_indicators_controller.rb +9 -0
- data/app/controllers/lab/test_types_controller.rb +15 -0
- data/app/controllers/lab/tests_controller.rb +25 -0
- data/app/controllers/lab/users_controller.rb +32 -0
- data/app/jobs/lab/application_job.rb +4 -0
- data/app/jobs/lab/push_order_job.rb +12 -0
- data/app/jobs/lab/update_patient_orders_job.rb +32 -0
- data/app/jobs/lab/void_order_job.rb +17 -0
- data/app/mailers/lab/application_mailer.rb +6 -0
- data/app/models/lab/application_record.rb +5 -0
- data/app/models/lab/lab_accession_number_counter.rb +13 -0
- data/app/models/lab/lab_acknowledgement.rb +6 -0
- data/app/models/lab/lab_encounter.rb +7 -0
- data/app/models/lab/lab_order.rb +58 -0
- data/app/models/lab/lab_result.rb +31 -0
- data/app/models/lab/lab_test.rb +19 -0
- data/app/models/lab/lims_failed_import.rb +4 -0
- data/app/models/lab/lims_order_mapping.rb +10 -0
- data/app/models/lab/order_extension.rb +14 -0
- data/app/serializers/lab/lab_order_serializer.rb +56 -0
- data/app/serializers/lab/result_serializer.rb +36 -0
- data/app/serializers/lab/test_serializer.rb +52 -0
- data/app/services/lab/accession_number_service.rb +77 -0
- data/app/services/lab/acknowledgement_service.rb +47 -0
- data/app/services/lab/concepts_service.rb +82 -0
- data/app/services/lab/json_web_token_service.rb +20 -0
- data/app/services/lab/labelling_service/order_label.rb +106 -0
- data/app/services/lab/lims/acknowledgement_serializer.rb +29 -0
- data/app/services/lab/lims/acknowledgement_worker.rb +37 -0
- data/app/services/lab/lims/api/blackhole_api.rb +21 -0
- data/app/services/lab/lims/api/couchdb_api.rb +53 -0
- data/app/services/lab/lims/api/mysql_api.rb +316 -0
- data/app/services/lab/lims/api/rest_api.rb +434 -0
- data/app/services/lab/lims/api/ws_api.rb +121 -0
- data/app/services/lab/lims/api_factory.rb +19 -0
- data/app/services/lab/lims/config.rb +105 -0
- data/app/services/lab/lims/exceptions.rb +11 -0
- data/app/services/lab/lims/migrator.rb +216 -0
- data/app/services/lab/lims/order_dto.rb +105 -0
- data/app/services/lab/lims/order_serializer.rb +251 -0
- data/app/services/lab/lims/pull_worker.rb +314 -0
- data/app/services/lab/lims/push_worker.rb +152 -0
- data/app/services/lab/lims/utils.rb +91 -0
- data/app/services/lab/lims/worker.rb +94 -0
- data/app/services/lab/metadata.rb +26 -0
- data/app/services/lab/notification_service.rb +72 -0
- data/app/services/lab/orders_search_service.rb +72 -0
- data/app/services/lab/orders_service.rb +330 -0
- data/app/services/lab/results_service.rb +166 -0
- data/app/services/lab/tests_service.rb +105 -0
- data/app/services/lab/user_service.rb +62 -0
- data/config/routes.rb +28 -0
- data/db/migrate/20210126092910_create_lab_lab_accession_number_counters.rb +12 -0
- data/db/migrate/20210310115457_create_lab_lims_order_mappings.rb +15 -0
- data/db/migrate/20210323080140_change_lims_id_to_string_in_lims_order_mapping.rb +15 -0
- data/db/migrate/20210326195504_add_order_revision_to_lims_order_mapping.rb +5 -0
- data/db/migrate/20210407071728_create_lab_lims_failed_imports.rb +19 -0
- data/db/migrate/20210610095024_fix_numeric_results_value_type.rb +20 -0
- data/db/migrate/20210807111531_add_default_to_lims_order_mapping.rb +7 -0
- data/lib/auto12epl.rb +201 -0
- data/lib/couch_bum/couch_bum.rb +92 -0
- data/lib/generators/lab/install/USAGE +9 -0
- data/lib/generators/lab/install/install_generator.rb +19 -0
- data/lib/generators/lab/install/templates/rswag-ui-lab.rb +5 -0
- data/lib/generators/lab/install/templates/start_worker.rb +32 -0
- data/lib/generators/lab/install/templates/swagger.yaml +714 -0
- data/lib/lab/engine.rb +13 -0
- data/lib/lab/version.rb +5 -0
- data/lib/logger_multiplexor.rb +38 -0
- data/lib/mahis_emr_api_lab.rb +6 -0
- data/lib/tasks/lab_tasks.rake +25 -0
- data/lib/tasks/loaders/data/reasons-for-test.csv +7 -0
- data/lib/tasks/loaders/data/test-measures.csv +225 -0
- data/lib/tasks/loaders/data/tests.csv +161 -0
- data/lib/tasks/loaders/loader_mixin.rb +53 -0
- data/lib/tasks/loaders/metadata_loader.rb +26 -0
- data/lib/tasks/loaders/reasons_for_test_loader.rb +23 -0
- data/lib/tasks/loaders/specimens_loader.rb +65 -0
- data/lib/tasks/loaders/test_result_indicators_loader.rb +54 -0
- metadata +331 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ce5389cf6e11fd5a6b5f220f8a5fec9ae5b08c9b2cfa26bddf0df79bbc34e739
|
4
|
+
data.tar.gz: 0e6cea217c13781dc92aeef61f03afef67cd9e21ab79909ed942a2dd7052f23b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 609b8532761b2cc4f144a6a1644de3275be4bf8c9134f8dbf96e2716d108eddf95f56a7f5b0c1c26b3b6554b5903c421b75e487de6b3f0b6cf23e57e8754360f
|
7
|
+
data.tar.gz: acc79fb836b4035659d48ae14b848454d36e6a1682fc15a68b9c8cde73021ac42759f31f11e64e17439d8b881bea9c7dbac889105b339898c81765e015f85d79
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 Walter Kaunda
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
![Ruby](https://github.com/EGPAFMalawiHIS/HIS-EMR-API-Lab/workflows/Ruby/badge.svg?branch=development)
|
2
|
+
# Lab
|
3
|
+
|
4
|
+
A Rails engine for [HIS-EMR-API](https://github.com/EGPAFMalawiHIS/HIS-EMR-API)
|
5
|
+
compatible applications that provides an API for managing various lab
|
6
|
+
activities.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
The engine provides an API that provides the following functionalities:
|
11
|
+
|
12
|
+
- Search/Retrieve test types
|
13
|
+
- Search/Retrieve sample types for a given test
|
14
|
+
- Order lab tests
|
15
|
+
- Attach a result to a test
|
16
|
+
|
17
|
+
For details on how to perform these operations please see the
|
18
|
+
[API docs](https://raw.githack.com/EGPAFMalawiHIS/HIS-EMR-API-Lab/development/docs/api.html).
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'lab', git: 'https://github.com/EGPAFMalawiHIS/HIS-EMR-API-Lab', branch: 'development'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
```bash
|
31
|
+
$ bundle install lab
|
32
|
+
```
|
33
|
+
|
34
|
+
Or install it yourself as:
|
35
|
+
|
36
|
+
```bash
|
37
|
+
$ gem install lab
|
38
|
+
```
|
39
|
+
|
40
|
+
Finally run:
|
41
|
+
|
42
|
+
```bash
|
43
|
+
$ bundle exec rails lab:install
|
44
|
+
```
|
45
|
+
|
46
|
+
## Configuration
|
47
|
+
|
48
|
+
This module in most cases should work without any configuration, however to enable
|
49
|
+
certain features some configuration may be required. Visit the
|
50
|
+
[configuration](./docs/configuration.md) page to learn how to configure the
|
51
|
+
application.
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
Fork this application create a branch for the contribution you want to make,
|
56
|
+
push your changes to the branch and then issue a pull request. You may want
|
57
|
+
to create a new first on our repository, so that your pull request references
|
58
|
+
this issue.
|
59
|
+
|
60
|
+
If you are fixing a bug, it will be nice to add a unit test that exposes
|
61
|
+
the bug. Although this is not a requirement in most cases.
|
62
|
+
|
63
|
+
Be sure to follow [this](https://github.com/rubocop/ruby-style-guide) Ruby
|
64
|
+
style guide. We don't necessarily look for strict adherence to the guidelines
|
65
|
+
but too much a departure from it is frowned upon. For example, you will be forgiven
|
66
|
+
for writing a method with 15 to 20 lines if you clearly justify why you couldn't
|
67
|
+
break that method into multiple smaller methods.
|
68
|
+
|
69
|
+
## License
|
70
|
+
|
71
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Lab'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'spec'
|
28
|
+
t.pattern = 'spec/**/*_spec.rb'
|
29
|
+
t.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class LabelsController < ApplicationController
|
5
|
+
skip_before_action :authenticate
|
6
|
+
|
7
|
+
def print_order_label
|
8
|
+
order_id = params.require(:order_id)
|
9
|
+
|
10
|
+
label = LabellingService::OrderLabel.new(order_id)
|
11
|
+
send_data(label.print, type: 'application/label; charset=utf-8',
|
12
|
+
stream: false,
|
13
|
+
filename: "#{SecureRandom.hex(24)}.lbl",
|
14
|
+
disposition: 'inline')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class OrdersController < ApplicationController
|
5
|
+
skip_before_action :authorize_request, only: %i[order_status order_result]
|
6
|
+
|
7
|
+
def create
|
8
|
+
order_params_list = params.require(:orders)
|
9
|
+
orders = order_params_list.map do |order_params|
|
10
|
+
OrdersService.order_test(order_params)
|
11
|
+
end
|
12
|
+
|
13
|
+
orders.each { |order| Lab::PushOrderJob.perform_later(order.fetch(:order_id)) }
|
14
|
+
|
15
|
+
render json: orders, status: :created
|
16
|
+
end
|
17
|
+
|
18
|
+
def update
|
19
|
+
specimen = params.require(:specimen).permit(:concept_id)
|
20
|
+
order = OrdersService.update_order(params[:id], specimen: specimen, force_update: params[:force_update])
|
21
|
+
Lab::PushOrderJob.perform_later(order.fetch(:order_id))
|
22
|
+
|
23
|
+
render json: order
|
24
|
+
end
|
25
|
+
|
26
|
+
def index
|
27
|
+
filters = params.permit(%i[patient_id patient accession_number date status])
|
28
|
+
|
29
|
+
id = filters[:patient_id] || filters[:patient]
|
30
|
+
|
31
|
+
patient = Patient.find(id) if filters[:patient_id] || filters[:patient]
|
32
|
+
|
33
|
+
Lab::UpdatePatientOrdersJob.perform_later(patient.id) if filters[:patient_id] || filters[:patient]
|
34
|
+
orders = OrdersSearchService.find_orders(filters)
|
35
|
+
begin
|
36
|
+
render json: orders.reload, status: :ok
|
37
|
+
rescue StandardError
|
38
|
+
render json: orders
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_tracking_number
|
43
|
+
tracking_number = params.require(:accession_number)
|
44
|
+
render json: { exists: OrdersService.check_tracking_number(tracking_number) }, status: :ok
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy
|
48
|
+
OrdersService.void_order(params[:id], params[:reason])
|
49
|
+
Lab::VoidOrderJob.perform_later(params[:id])
|
50
|
+
|
51
|
+
render status: :no_content
|
52
|
+
end
|
53
|
+
|
54
|
+
def order_status
|
55
|
+
order_params = params.permit(:tracking_number, :status, :status_time, :comments)
|
56
|
+
OrdersService.update_order_status(order_params)
|
57
|
+
render json: { message: "Status for order #{order_params['tracking_number']} successfully updated" }, status: :ok
|
58
|
+
end
|
59
|
+
|
60
|
+
def order_result
|
61
|
+
params.permit!
|
62
|
+
order_params = params[:data].to_h
|
63
|
+
OrdersService.update_order_result(order_params)
|
64
|
+
render json: { message: 'Results processed successfully' }, status: :ok
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def authenticate_request
|
70
|
+
decoded_user = authorize_request
|
71
|
+
user(decoded_user)
|
72
|
+
end
|
73
|
+
|
74
|
+
def user(decoded)
|
75
|
+
User.current = User.find decoded[:user_id]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class ResultsController < ApplicationController
|
5
|
+
def create
|
6
|
+
result_params = params.require(:result)
|
7
|
+
.permit([:encounter_id,
|
8
|
+
:encounter,
|
9
|
+
:date,
|
10
|
+
{ measures: [:value,
|
11
|
+
:value_type,
|
12
|
+
:value_modifier,
|
13
|
+
{ indicator: %i[concept_id concept] }] }])
|
14
|
+
|
15
|
+
result = Lab::ResultsService.create_results(params[:test_id], result_params, 'user entered')
|
16
|
+
|
17
|
+
render json: result, status: :created
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class SpecimenTypesController < ApplicationController
|
5
|
+
def index
|
6
|
+
filters = params.permit(%w[name test_type])
|
7
|
+
|
8
|
+
specimen_types = ConceptsService.specimen_types(name: filters['name'],
|
9
|
+
test_type: filters['test_type'])
|
10
|
+
.as_json(only: %w[concept_id name])
|
11
|
+
|
12
|
+
render json: specimen_types
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class TestTypesController < ApplicationController
|
5
|
+
def index
|
6
|
+
filters = params.permit(%w[name specimen_type])
|
7
|
+
|
8
|
+
test_types = ConceptsService.test_types(name: filters['name'],
|
9
|
+
specimen_type: filters['specimen_type'])
|
10
|
+
.as_json(only: %w[concept_id name])
|
11
|
+
|
12
|
+
render json: test_types
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Lab::TestsController < ::ApplicationController
|
4
|
+
def index
|
5
|
+
filters = params.permit(%i[order_date accession_number patient patient_id test_type_id specimen_type_id pending_results])
|
6
|
+
tests = service.find_tests(filters)
|
7
|
+
render json: tests
|
8
|
+
end
|
9
|
+
|
10
|
+
# Add a specimen to an existing order
|
11
|
+
def create
|
12
|
+
test_params = params.permit(:order_id, :date, tests: [:concept_id])
|
13
|
+
order_id, test_concepts = test_params.require(%i[order_id tests])
|
14
|
+
date = test_params[:date] || Date.today
|
15
|
+
|
16
|
+
tests = service.create_tests(Lab::LabOrder.find(order_id), date, test_concepts)
|
17
|
+
Lab::PushOrderJob.perform_later(order_id)
|
18
|
+
|
19
|
+
render json: tests, status: :created
|
20
|
+
end
|
21
|
+
|
22
|
+
def service
|
23
|
+
Lab::TestsService
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This controller handles creation and authentication of LIMS User
|
4
|
+
module Lab
|
5
|
+
class UsersController < ::ApplicationController
|
6
|
+
skip_before_action :authenticate
|
7
|
+
# create a LIMS User that will be responsible for sending lab results
|
8
|
+
def create
|
9
|
+
user_params = params.permit(:username, :password)
|
10
|
+
service.create_lims_user(username: user_params['username'], password: user_params['password'])
|
11
|
+
render json: { message: 'User successfully created' }, status: 200
|
12
|
+
end
|
13
|
+
|
14
|
+
# authenticate the lims user
|
15
|
+
def login
|
16
|
+
user_params = params.permit(:username, :password)
|
17
|
+
result = service.authenticate_user(username: user_params['username'], password: user_params['password'],
|
18
|
+
user_agent: request.user_agent, request_ip: request.remote_ip)
|
19
|
+
if result.present?
|
20
|
+
render json: result, status: 200
|
21
|
+
else
|
22
|
+
render json: { message: 'Invalid Credentials Provided' }, status: 401
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def service
|
29
|
+
Lab::UserService
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
##
|
5
|
+
# Push an order to LIMS.
|
6
|
+
class PushOrderJob < ApplicationJob
|
7
|
+
def perform(order_id)
|
8
|
+
push_worker = Lab::Lims::PushWorker.new(Lab::Lims::ApiFactory.create_api)
|
9
|
+
push_worker.push_order_by_id(order_id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
##
|
5
|
+
# Fetches updates on a patient's orders from external sources.
|
6
|
+
class UpdatePatientOrdersJob < ApplicationJob
|
7
|
+
queue_as :default
|
8
|
+
|
9
|
+
def perform(patient_id)
|
10
|
+
Rails.logger.info('Initialising LIMS REST API...')
|
11
|
+
|
12
|
+
User.current = Lab::Lims::Utils.lab_user
|
13
|
+
Location.current = Location.find_by_name('ART clinic')
|
14
|
+
|
15
|
+
lockfile = Rails.root.join('tmp', "update-patient-orders-#{patient_id}.lock")
|
16
|
+
|
17
|
+
done = File.open(lockfile, File::RDWR | File::CREAT) do |lock|
|
18
|
+
unless lock.flock(File::LOCK_NB | File::LOCK_EX)
|
19
|
+
Rails.logger.info('Another update patient job is already running...')
|
20
|
+
break false
|
21
|
+
end
|
22
|
+
|
23
|
+
worker = Lab::Lims::PullWorker.new(Lab::Lims::ApiFactory.create_api)
|
24
|
+
worker.pull_orders(patient_id: patient_id)
|
25
|
+
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
File.unlink(lockfile) if done
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class VoidOrderJob < ApplicationJob
|
5
|
+
queue_as :default
|
6
|
+
|
7
|
+
def perform(order_id)
|
8
|
+
Rails.logger.info("Voiding order ##{order_id} in LIMS")
|
9
|
+
|
10
|
+
User.current = Lab::Lims::Utils.lab_user
|
11
|
+
Location.current = Location.find_by_name('ART clinic')
|
12
|
+
|
13
|
+
worker = Lab::Lims::PushWorker.new(Lab::Lims::ApiFactory.create_api)
|
14
|
+
worker.push_order(Lab::LabOrder.unscoped.find(order_id))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
# Used to keep track of counters for accession numbers.
|
5
|
+
#
|
6
|
+
# An accession number is just a prefix plus a running encounter
|
7
|
+
# that's reset at the end of the day
|
8
|
+
class LabAccessionNumberCounter < ApplicationRecord
|
9
|
+
self.table_name = :lab_accession_number_counters
|
10
|
+
|
11
|
+
validates_presence_of :date, :value
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class LabOrder < ::Order
|
5
|
+
class << self
|
6
|
+
def make_obs_concept_filter(concept_name)
|
7
|
+
concept = ConceptName.where(name: concept_name).select(:concept_id)
|
8
|
+
|
9
|
+
-> { where(concept: concept) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
has_many :tests,
|
14
|
+
make_obs_concept_filter(Lab::Metadata::TEST_TYPE_CONCEPT_NAME),
|
15
|
+
class_name: '::Lab::LabTest',
|
16
|
+
foreign_key: :order_id
|
17
|
+
|
18
|
+
has_many :results,
|
19
|
+
make_obs_concept_filter(Lab::Metadata::TEST_RESULT_CONCEPT_NAME),
|
20
|
+
class_name: 'Observation',
|
21
|
+
foreign_key: :order_id
|
22
|
+
|
23
|
+
has_one :reason_for_test,
|
24
|
+
make_obs_concept_filter(Lab::Metadata::REASON_FOR_TEST_CONCEPT_NAME),
|
25
|
+
class_name: 'Observation',
|
26
|
+
foreign_key: :order_id
|
27
|
+
|
28
|
+
has_one :requesting_clinician,
|
29
|
+
make_obs_concept_filter(Lab::Metadata::REQUESTING_CLINICIAN_CONCEPT_NAME),
|
30
|
+
class_name: 'Observation',
|
31
|
+
foreign_key: :order_id
|
32
|
+
|
33
|
+
has_one :target_lab,
|
34
|
+
make_obs_concept_filter(Lab::Metadata::TARGET_LAB_CONCEPT_NAME),
|
35
|
+
class_name: 'Observation',
|
36
|
+
foreign_key: :order_id
|
37
|
+
|
38
|
+
has_one :mapping,
|
39
|
+
class_name: '::Lab::LimsOrderMapping',
|
40
|
+
foreign_key: :order_id
|
41
|
+
|
42
|
+
default_scope do
|
43
|
+
joins(:order_type)
|
44
|
+
.merge(OrderType.where(name: Lab::Metadata::ORDER_TYPE_NAME))
|
45
|
+
.where.not(concept_id: ConceptName.where(name: 'Tests ordered').select(:concept_id))
|
46
|
+
end
|
47
|
+
|
48
|
+
scope :drawn, -> { where.not(concept_id: ConceptName.where(name: 'Unknown').select(:concept_id)) }
|
49
|
+
scope :not_drawn, -> { where(concept_id: ConceptName.where(name: 'Unknown').select(:concept_id)) }
|
50
|
+
|
51
|
+
def self.prefetch_relationships
|
52
|
+
includes(:reason_for_test,
|
53
|
+
:requesting_clinician,
|
54
|
+
:target_lab,
|
55
|
+
tests: [:result])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class LabResult < Observation
|
5
|
+
alias measures children
|
6
|
+
|
7
|
+
default_scope do
|
8
|
+
lab_test_concept = ConceptName.where(name: Lab::Metadata::TEST_RESULT_CONCEPT_NAME)
|
9
|
+
.select(:concept_id)
|
10
|
+
where(voided: 0, concept: lab_test_concept)
|
11
|
+
end
|
12
|
+
|
13
|
+
belongs_to :test,
|
14
|
+
(lambda do
|
15
|
+
where(concept: ConceptName.where(name: Lab::Metadata::TEST_TYPE_CONCEPT_NAME)
|
16
|
+
.select(:concept_id))
|
17
|
+
end),
|
18
|
+
class_name: 'Observation',
|
19
|
+
foreign_key: :obs_group_id
|
20
|
+
|
21
|
+
def void(reason)
|
22
|
+
children.each do |measure|
|
23
|
+
# Need to have a LabResultMeasure model that privately handles it's children
|
24
|
+
measure.children.each { |provider| provider.void(reason) }
|
25
|
+
measure.void(reason)
|
26
|
+
end
|
27
|
+
|
28
|
+
super(reason)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class LabTest < ::Observation
|
5
|
+
default_scope do
|
6
|
+
where(concept: ConceptName.where(name: Lab::Metadata::TEST_TYPE_CONCEPT_NAME))
|
7
|
+
end
|
8
|
+
|
9
|
+
has_one :result,
|
10
|
+
-> { where(concept: ConceptName.where(name: Lab::Metadata::TEST_RESULT_CONCEPT_NAME)) },
|
11
|
+
class_name: 'Lab::LabResult',
|
12
|
+
foreign_key: :obs_group_id
|
13
|
+
|
14
|
+
def void(reason)
|
15
|
+
result&.void(reason)
|
16
|
+
super(reason)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab
|
4
|
+
class LimsOrderMapping < ApplicationRecord
|
5
|
+
belongs_to :order, class_name: 'LabOrder', foreign_key: 'order_id'
|
6
|
+
|
7
|
+
validates_presence_of :lims_id, :order_id
|
8
|
+
validates_uniqueness_of :lims_id, :order_id
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# model managing extra details for orders
|
4
|
+
class Lab::OrderExtension < ApplicationRecord
|
5
|
+
include Voidable
|
6
|
+
self.table_name = :order_extension
|
7
|
+
self.primary_key = :order_extension_id
|
8
|
+
|
9
|
+
default_scope { where(voided: 0) }
|
10
|
+
scope :voided, -> { unscoped.where.not(voided: 0) }
|
11
|
+
|
12
|
+
belongs_to :order, foreign_key: :order_id
|
13
|
+
belongs_to :creator, class_name: 'User', foreign_key: :creator
|
14
|
+
end
|