aqi 0.0.3
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/aqi.gemspec +19 -0
- data/lib/aqi/anesthesia_case.rb +34 -0
- data/lib/aqi/anesthesia_detail.rb +10 -0
- data/lib/aqi/anesthesia_record.rb +83 -0
- data/lib/aqi/anesthesia_records.rb +30 -0
- data/lib/aqi/anesthesia_staff.rb +42 -0
- data/lib/aqi/cpt.rb +26 -0
- data/lib/aqi/demographic.rb +26 -0
- data/lib/aqi/ic_event.rb +51 -0
- data/lib/aqi/intake_output_set.rb +13 -0
- data/lib/aqi/intubation_detail.rb +16 -0
- data/lib/aqi/outcome.rb +94 -0
- data/lib/aqi/outcome_events.rb +41 -0
- data/lib/aqi/pre_op.rb +109 -0
- data/lib/aqi/procedure.rb +70 -0
- data/lib/aqi/procedure_location.rb +34 -0
- data/lib/aqi/record_header.rb +18 -0
- data/lib/aqi/version.rb +3 -0
- data/lib/aqi.rb +45 -0
- metadata +70 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Robert Jackson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Aqi
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'aqi'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install aqi
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/aqi.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'aqi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "aqi"
|
8
|
+
gem.version = AQI::VERSION
|
9
|
+
gem.authors = ["Robert Jackson"]
|
10
|
+
gem.email = ["robertj@promedicalinc.com"]
|
11
|
+
gem.description = %q{Generates output based on the AQI schema.}
|
12
|
+
gem.summary = %q{Generates output based on the AQI schema.}
|
13
|
+
gem.homepage = "https://github.com/promedical/aqi"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AQI
|
2
|
+
class AnesthesiaCase
|
3
|
+
attr_accessor :anesthesia_record_id, :anesthesia_coverage, :anesthesia_staff_set, :monitoring_set
|
4
|
+
|
5
|
+
def self.anesthesia_coverages
|
6
|
+
["MD-ALONE", "MD-DIRECTING", "CRNA-DIRECTED", "CRNA-ALONE",
|
7
|
+
"MD-SUPERVISING", "CRNA-DIRECTING", "MD-MD"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
self.anesthesia_record_id = options[:anesthesia_record_id]
|
12
|
+
self.anesthesia_coverage = validate_anesthesia_coverage(options[:anesthesia_coverage])
|
13
|
+
self.anesthesia_staff_set = options[:anesthesia_staff_set] || []
|
14
|
+
self.monitoring_set = options[:monitoring_set] || []
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_anesthesia_coverage(value)
|
18
|
+
self.class.anesthesia_coverages.include?(value) ? value : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_xml
|
22
|
+
builder = Builder::XmlMarkup.new
|
23
|
+
builder.AnesthesiaCase do |ac|
|
24
|
+
ac.AnesthesiaRecordID(anesthesia_record_id)
|
25
|
+
ac.AnesthesiaCoverage(anesthesia_coverage) if anesthesia_coverage
|
26
|
+
ac.AnesthesiaStaffSet do |ass|
|
27
|
+
anesthesia_staff_set.each do |as|
|
28
|
+
ass << as.to_xml
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module AQI
|
2
|
+
class AnesthesiaDetails
|
3
|
+
attr_accessor :intake_output_set_type, :intubation_details, :anesthesia_detils_set, :medications_total_set
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
self.intake_output_set_type = IntakeOutputSet.new(options.delete(:intake_output_set))
|
7
|
+
self.intubation_details = IntubationDetails.new(options.delete(:intubation_details))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module AQI
|
2
|
+
class AnesthesiaRecord
|
3
|
+
attr_accessor :encounter
|
4
|
+
|
5
|
+
def initialize(encounter)
|
6
|
+
self.encounter = encounter
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_xml
|
10
|
+
builder = Builder::XmlMarkup.new
|
11
|
+
builder.AnesthesiaRecord do |ar|
|
12
|
+
ar << demographic.to_xml
|
13
|
+
ar << procedure.to_xml
|
14
|
+
ar << anesthesia_case.to_xml
|
15
|
+
ar << pre_op.to_xml
|
16
|
+
ar << outcome_events.to_xml
|
17
|
+
#ar << post_op
|
18
|
+
#ar << timing_milestones
|
19
|
+
#ar << outcomes_events
|
20
|
+
#ar << anesthesia_details
|
21
|
+
#ar << ic_event_set
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def demographic
|
26
|
+
Demographic.new(date_of_birth: encounter.date_of_birth,
|
27
|
+
postal_code: encounter.postal_code,
|
28
|
+
state: encounter.state,
|
29
|
+
city: encounter.city,
|
30
|
+
gender: encounter.gender)
|
31
|
+
end
|
32
|
+
|
33
|
+
def outcome_events
|
34
|
+
outcomes = encounter.adverse_events.collect do |ae|
|
35
|
+
{time_date: encounter.date_of_service, name: ae}
|
36
|
+
end
|
37
|
+
|
38
|
+
OutcomeEvents.new(outcomes: outcomes)
|
39
|
+
end
|
40
|
+
|
41
|
+
def services
|
42
|
+
@services ||= encounter.services + encounter.pqrs_services
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_time
|
46
|
+
services.map{|s| s.start_time}.min
|
47
|
+
end
|
48
|
+
|
49
|
+
def end_time
|
50
|
+
services.map{|s| s.end_time}.max
|
51
|
+
end
|
52
|
+
|
53
|
+
def cpt_set
|
54
|
+
services.collect{|s| CPT.new(value: s.procedure_code)}
|
55
|
+
end
|
56
|
+
|
57
|
+
def procedure
|
58
|
+
Procedure.new(procedure_id: encounter.encounter_id,
|
59
|
+
facility_id: encounter.location_id,
|
60
|
+
start_time: start_time,
|
61
|
+
end_time: end_time,
|
62
|
+
location_type: encounter.place_of_service,
|
63
|
+
location_details: encounter.location_name,
|
64
|
+
cpt_set: cpt_set)
|
65
|
+
end
|
66
|
+
|
67
|
+
def anesthesia_staffs
|
68
|
+
services.collect do |s|
|
69
|
+
AnesthesiaStaff.new(staff_id: s.provider_id, role: s.provider_type)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def anesthesia_case
|
74
|
+
AnesthesiaCase.new(anesthesia_record_id: encounter.encounter_id,
|
75
|
+
anesthesia_staff_set: anesthesia_staffs)
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def pre_op
|
80
|
+
PreOp.new(age: encounter.patient_age, icd_set: encounter.diagnosis_codes, asa_class: encounter.asa_class)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AQI
|
2
|
+
class AnesthesiaRecords
|
3
|
+
attr_accessor :encounters, :practice_id
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
self.encounters = options.delete(:encounters)
|
7
|
+
self.practice_id = options.delete(:practice_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
def record_header
|
11
|
+
RecordHeader.new(practice_id).to_xml
|
12
|
+
end
|
13
|
+
|
14
|
+
def anesthesia_records
|
15
|
+
encounters.collect{|e| AnesthesiaRecord.new(e)}
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_xml
|
19
|
+
builder = Builder::XmlMarkup.new
|
20
|
+
builder.instruct!
|
21
|
+
builder.AnesthesiaRecords do |ars|
|
22
|
+
ars << record_header
|
23
|
+
|
24
|
+
anesthesia_records.each do |anes_record|
|
25
|
+
ars << anes_record.to_xml
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AQI
|
2
|
+
class AnesthesiaStaff
|
3
|
+
attr_accessor :staff_id, :responsibility, :role, :sign_in, :sign_out, :notes
|
4
|
+
|
5
|
+
def self.responsibilities
|
6
|
+
["Supervisory", "Monitoring", "Administrative", "In charge", "Performing the case", "Medically responsible"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.roles
|
10
|
+
["MD", "CRNA", "DO", "RESIDENT", "PACU Nurse", "AA"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
self.staff_id = options[:staff_id]
|
15
|
+
self.responsibility = validate_responsibility(options[:responsibility])
|
16
|
+
self.role = validate_role(options[:role])
|
17
|
+
self.sign_in = options[:sign_in]
|
18
|
+
self.sign_out = options[:sign_out]
|
19
|
+
self.notes = options[:notes]
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate_responsibility(value)
|
23
|
+
self.class.responsibilities.include?(value) ? value : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_role(value)
|
27
|
+
self.class.roles.include?(value) ? value : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_xml
|
31
|
+
builder = Builder::XmlMarkup.new
|
32
|
+
builder.AnesthesiaStaff do |as|
|
33
|
+
as.StaffID(staff_id)
|
34
|
+
as.StaffResponsibility(responsibility) if responsibility
|
35
|
+
as.StaffRole(role) if role
|
36
|
+
as.StaffSignIn(sign_in.strftime('%FT%T')) if sign_in
|
37
|
+
as.StaffSignOut(sign_out.strftime('%FT%T')) if sign_out
|
38
|
+
as.StaffNotes(notes) if notes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/aqi/cpt.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module AQI
|
2
|
+
class CPT
|
3
|
+
attr_accessor :rank, :value, :modifier
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
self.rank = options[:rank]
|
7
|
+
self.value = validate_value(options[:value])
|
8
|
+
self.modifier = options[:modifier]
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_value(value)
|
12
|
+
value =~ /\d\d\d\d[\w\d]/ ? value : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
return '' unless value
|
17
|
+
|
18
|
+
builder = Builder::XmlMarkup.new
|
19
|
+
builder.CPT do |cpt|
|
20
|
+
cpt.CPTRank(rank) if rank
|
21
|
+
cpt.CPTValue(value)
|
22
|
+
cpt.CPTModifier(modifier) if modifier
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AQI
|
2
|
+
class Demographic
|
3
|
+
attr_accessor :date_of_birth, :postal_code, :state, :city, :race, :gender
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
self.date_of_birth = options[:date_of_birth]
|
7
|
+
self.postal_code = options[:postal_code]
|
8
|
+
self.state = options[:state]
|
9
|
+
self.city = options[:city]
|
10
|
+
self.race = options[:race]
|
11
|
+
self.gender = options[:gender]
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml
|
15
|
+
builder = Builder::XmlMarkup.new
|
16
|
+
builder.Demographic do |d|
|
17
|
+
d.DOB(date_of_birth.strftime('%F')) if date_of_birth
|
18
|
+
d.HomeZip(postal_code)
|
19
|
+
d.HomeState(state)
|
20
|
+
d.HomeCity(city)
|
21
|
+
d.Race(race || 'UNKNOWN')
|
22
|
+
d.Gender(gender)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/aqi/ic_event.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module AQI
|
2
|
+
class ICEvent
|
3
|
+
attr_accessor :event_time_date, :category, :severity, :name, :description, :value, :notes
|
4
|
+
|
5
|
+
def self.categories
|
6
|
+
["MEDICAL DEVICE/EQUIPMENT","MEDICATION", "INFRASTRUCTURE/SYSTEM", "ASSESSMENT/DOCUMENTATION",
|
7
|
+
"RESPIRATORY/AIRWAY", "CARDIOVASCULAR", "PROCEDURE RELATED", "OTHER", "UNKNOWN" ]
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
self.event_time_date = options.delete(:event_time_date)
|
12
|
+
self.category = options.delete(:category)
|
13
|
+
self.severity = options.delete(:severity)
|
14
|
+
self.name = options.delete(:name)
|
15
|
+
self.description = options.delete(:description)
|
16
|
+
self.value = options.delete(:value)
|
17
|
+
self.notes = options.delete(:notes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_category(value)
|
21
|
+
self.class.categories.include?(value) ? value : "UNKNOWN"
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_xml
|
25
|
+
builder = Builder::XmlMarkup.new
|
26
|
+
builder.ICEvent do |ice|
|
27
|
+
ice.ICEventTimeDate(event_time_date.strftime('%FT%T')) if event_time_date
|
28
|
+
ice.ICCategory(validate_category(category))
|
29
|
+
ice.ICSeverity(severity)
|
30
|
+
ice.ICName(name)
|
31
|
+
ice.ICDesciption(description)
|
32
|
+
ice.ICValue(value)
|
33
|
+
ice.ICNotes(notes)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ICEventsPreparer
|
39
|
+
def self.prepare_ic_events(outcome_events)
|
40
|
+
ic_events = outcome_events.ic_events
|
41
|
+
|
42
|
+
ic_events.collect do |event|
|
43
|
+
self.ic_event.new(event)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.ic_event
|
48
|
+
ICEvent
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module AQI
|
2
|
+
class IntakeOutputSet
|
3
|
+
attr_accessor :output_direction, :output_name, :output_units, :input_output_total, :input_output_route
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
self.output_direction = options.delete(:output_direction)
|
7
|
+
self.output_name = options.delete(:output_name)
|
8
|
+
self.output_units = options.delete(:output_units)
|
9
|
+
self.input_output_total = options.delete(:input_output_total)
|
10
|
+
self.input_output_route = options.delete(:input_output_route)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AQI
|
2
|
+
class IntubationDetail
|
3
|
+
attr_accessor :intubation_approach, :intubation_attempts, :tube_size, :tube_type, :intubation_details_properties_set
|
4
|
+
|
5
|
+
def self.approach_types
|
6
|
+
["Endoctracheal", "Nasogastric", "Nasotracheal", "Fiberoptic", "Tracheostomy", "Speaking tracheostomy", "OTHER", "UNKNOWN"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
self.intubation_approach = options.delete(:intubation_approach)
|
11
|
+
self.intubation_attempts = options.delete(:intubation_attempts)
|
12
|
+
self.tube_size = options.delete(:tube_size)
|
13
|
+
self.tube_type = options.delete(:intubation_details_properties_set) # Class
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/aqi/outcome.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module AQI
|
2
|
+
class Outcome
|
3
|
+
attr_accessor :time_date, :time_frame, :severity_code, :category_code, :sub_category_code, :location_type_code, :name, :description, :value, :range_min, :range_max, :notes
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
self.time_date = options.delete(:time_date)
|
7
|
+
self.time_frame = options.delete(:time_frame)
|
8
|
+
self.severity_code = options.delete(:severity_code)
|
9
|
+
self.category_code = options.delete(:category_code)
|
10
|
+
self.sub_category_code = options.delete(:sub_category_code)
|
11
|
+
self.location_type_code = options.delete(:location_type_code)
|
12
|
+
self.name = options.delete(:name)
|
13
|
+
self.description = options.delete(:description)
|
14
|
+
self.value = options.delete(:value)
|
15
|
+
self.range_min = options.delete(:range_min)
|
16
|
+
self.range_max = options.delete(:range_max)
|
17
|
+
self.notes = options.delete(:notes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.time_frames
|
21
|
+
["PreOp", "IntraOp", "PACU", "24h", "48h", "Week", "Month"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.severities
|
25
|
+
["NoEffect", "PotentialHazard", "LossOfTime", "LossOfMoney", "HarmToPatient", "SevereHarmToPatient", "PermanentDisability", "Death"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.categories
|
29
|
+
["PatientSurvey", "Outcome", "OTHER", "UNKNOWN"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.sub_categories
|
33
|
+
["MEDICAL DEVICE/EQUIPMENT", "MEDICATION", "INFRASTRUCTURE/SYSTEM", "ASSESSMENT/DOCUMENTATION", "RESPIRATORY/AIRWAY", "CARDIOVASCULAR", "PROCEDURE RELATED", "OTHER", "UNKNOWN"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.location_codes
|
37
|
+
["In-Patient", "Post In-Patient", "Out-Patient", "Post Out-Patient", "Obstetrics", "Surgery Center", "Surgery Center Post Out-Patient", "Office", "Home", "Ambulatory Surgical Center", "Pharmacy", "Skilled Nursing Facility", "Ambulance - Land", "Emergency Room Hospital", "Urgent Care Facility", "Inpatient Psychiatric Facility", "School", "Custodial Care Facility", "Residential Substance Abuse Treatment Facility", "Military Treatment Facility", "OTHER", "UNKNOWN"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_xml
|
41
|
+
builder = Builder::XmlMarkup.new
|
42
|
+
builder.Outcome do |o|
|
43
|
+
o.OutcomeTimeDate(time_date.strftime('%FT%T')) if time_date
|
44
|
+
o.OutcomeTimeFrame(validate_time_frames(time_frame)) if time_frame
|
45
|
+
o.OutcomeSeverity(validate_severity(severity_code)) if severity_code
|
46
|
+
o.OutcomeCategory(validate_category(category_code)) if category_code
|
47
|
+
o.OutcomeSubcategory(validate_sub_category(sub_category_code)) if sub_category_code
|
48
|
+
o.OutcomeLocation(validate_location_code(location_type_code)) if location_type_code
|
49
|
+
o.OutcomeName(name) if name
|
50
|
+
o.OutcomeDesciption(description) if description
|
51
|
+
o.OutcomeValue(value) if value
|
52
|
+
o.OutcomeRangeMin(range_min) if range_min
|
53
|
+
o.OutcomeRangeMax(range_max) if range_max
|
54
|
+
o.OutcomeNotes(notes) if notes
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def validate_category(value)
|
61
|
+
self.class.categories.include?(value) ? value : "UNKNOWN"
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_time_frames(value)
|
65
|
+
self.class.time_frames.include?(value) ? value : ""
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_severity(value)
|
69
|
+
self.class.severities.include?(value) ? value : "NoEffect"
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate_sub_category(value)
|
73
|
+
self.class.sub_categories.include?(value) ? value : "UNKNOWN"
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_location_code(value)
|
77
|
+
self.class.location_codes.include?(value) ? value : "UNKNOWN"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class OutcomesPreparer
|
82
|
+
def self.prepare_outcomes(outcome_events)
|
83
|
+
outcomes = outcome_events.outcomes
|
84
|
+
|
85
|
+
outcomes.collect do |o|
|
86
|
+
self.outcome.new(o)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.outcome
|
91
|
+
Outcome
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module AQI
|
2
|
+
class OutcomeEvents
|
3
|
+
attr_accessor :ic_events, :outcomes, :event_preparer, :outcomes_preparer
|
4
|
+
def initialize(options)
|
5
|
+
@event_preparer = options.delete(:event_preparer) || AQI::ICEventsPreparer
|
6
|
+
@ic_events = options.delete(:ic_events) || []
|
7
|
+
@outcomes_preparer = options.delete(:outcomes_preparer) || AQI::OutcomesPreparer
|
8
|
+
@outcomes = options.delete(:outcomes) || []
|
9
|
+
prepare
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
prepare_ic_events
|
14
|
+
prepare_outcomes
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare_ic_events
|
18
|
+
self.ic_events = event_preparer.prepare_ic_events(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def prepare_outcomes
|
22
|
+
self.outcomes = outcomes_preparer.prepare_outcomes(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_xml
|
26
|
+
builder = Builder::XmlMarkup.new
|
27
|
+
builder.OutcomesEvents do |oe|
|
28
|
+
oe.ICEventSet do |ic_set|
|
29
|
+
self.ic_events.each do |event|
|
30
|
+
ic_set.ICEvent << event.to_xml
|
31
|
+
end
|
32
|
+
end
|
33
|
+
oe.OutcomeSet do |outcome_set|
|
34
|
+
self.outcomes.each do |outcome|
|
35
|
+
outcome_set.Outcome << outcome.to_xml
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/aqi/pre_op.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
class PreOp
|
2
|
+
|
3
|
+
ICD = Struct.new(:rank, :value) do
|
4
|
+
def to_xml
|
5
|
+
builder = Builder::XmlMarkup.new
|
6
|
+
builder.ICD do |icd|
|
7
|
+
icd.ICDRank(rank)
|
8
|
+
icd.ICDValue(value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
PreRisk = Struct.new(:category, :name, :notes) do
|
14
|
+
def to_xml
|
15
|
+
builder = Builder::XmlMarkup.new
|
16
|
+
builder.PreRisk do |prs|
|
17
|
+
prs.PreOPRiskCategory(category)
|
18
|
+
prs.PreOPRiskName(name)
|
19
|
+
prs.PreOPRiskNotes(notes)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_accessor :age, :weight_pounds, :height_inches, :asa_class, :pre_anesthesia_status, :icd_set, :pre_risk_set
|
25
|
+
|
26
|
+
def initialize(options)
|
27
|
+
self.age = validate_age(options.delete(:age))
|
28
|
+
self.weight_pounds = options.delete(:weight_pounds)
|
29
|
+
self.height_inches = options.delete(:height_inches)
|
30
|
+
self.asa_class = validate_asa_class(options.delete(:asa_class))
|
31
|
+
self.pre_anesthesia_status = validate_pre_anesthesia_status(options.delete(:pre_anesthesia_status))
|
32
|
+
|
33
|
+
self.icd_set = setup_icd_set(options.delete(:icd_set))
|
34
|
+
self.pre_risk_set = setup_pre_risk_set(options.delete(:pre_risk_set))
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.asa_classes
|
38
|
+
["I", "II", "III", "IV", "V", "VI", "IE", "IIE", "IIIE", "IVE", "VE", "VIE"]
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.pre_anesthesia_statuses
|
42
|
+
["Awake", "Awake", "Asleep", "Confused", "Unresponsive", "Apprehensive", "Uncooperative", "OTHER", "UNKNOWN"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def height_in_cm
|
46
|
+
self.height_inches.to_f / 0.3937
|
47
|
+
end
|
48
|
+
|
49
|
+
def weight_in_kg
|
50
|
+
self.weight_pounds.to_f / 0.45359
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_xml
|
54
|
+
builder = Builder::XmlMarkup.new
|
55
|
+
builder.PreOp do |pre|
|
56
|
+
pre.Age(age) if age
|
57
|
+
pre.Weight(weight_pounds) if weight_pounds
|
58
|
+
pre.WeightInKg(weight_in_kg) if weight_pounds
|
59
|
+
pre.Height(height_inches) if height_inches
|
60
|
+
pre.HeightInCm(height_in_cm) if height_inches
|
61
|
+
pre.ASAClass(asa_class) if asa_class
|
62
|
+
pre.PreAnesthStatus(pre_anesthesia_status) if pre_anesthesia_status
|
63
|
+
|
64
|
+
pre.ICDSet do |set|
|
65
|
+
icd_set.each do |icd|
|
66
|
+
set << icd.to_xml
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
pre.PreRiskSet do |set|
|
71
|
+
pre_risk_set.each do |prs|
|
72
|
+
set << prs.to_xml
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# pre.PreLabSet
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def setup_pre_risk_set(set)
|
83
|
+
return [] if set.nil?
|
84
|
+
|
85
|
+
set.collect do |args|
|
86
|
+
PreRisk.new(*args)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def setup_icd_set(set)
|
91
|
+
return [] if set.nil?
|
92
|
+
|
93
|
+
set.collect.with_index do |icd, index|
|
94
|
+
ICD.new(index + 1, icd)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_age(value)
|
99
|
+
value.to_i > 0 ? value.to_i : nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate_asa_class(value)
|
103
|
+
self.class.asa_classes.include?(value) ? value : nil # no default
|
104
|
+
end
|
105
|
+
|
106
|
+
def validate_pre_anesthesia_status(value)
|
107
|
+
self.class.pre_anesthesia_statuses.include?(value) ? value : nil
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module AQI
|
2
|
+
class Procedure
|
3
|
+
attr_accessor :procedure_id, :facility_id, :location, :location_type, :location_details,
|
4
|
+
:start_time, :end_time, :admission_status, :status, :transfer_status,
|
5
|
+
:admission_date, :notes, :cpt_set
|
6
|
+
|
7
|
+
def self.admission_statuses
|
8
|
+
%w{Emergency Inpatient Outpatient Urgent OTHER UNKNOWN}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.statuses
|
12
|
+
%w{Emergent Urgent Elective OTHER UNKNOWN}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.transfer_statuses
|
16
|
+
["Floor bed", "Observation unit", "Telemetry/step-down unit", "Home with services", "Died",
|
17
|
+
"Operating Room", "Intensive Care Unit", "Home without services", "Left against medical advice",
|
18
|
+
"Transferred to another hospital", "OTHER", "UNKNOWN"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(options)
|
22
|
+
self.procedure_id = options[:procedure_id]
|
23
|
+
self.facility_id = options[:facility_id]
|
24
|
+
self.start_time = options[:start_time]
|
25
|
+
self.end_time = options[:end_time]
|
26
|
+
self.admission_status = validate_admission_status(options[:admission_status])
|
27
|
+
self.status = validate_status(options[:status])
|
28
|
+
self.transfer_status = validate_transfer_status(options[:transfer_status])
|
29
|
+
self.admission_date = options[:admission_date]
|
30
|
+
self.notes = options[:notes]
|
31
|
+
self.cpt_set = options[:cpt_set] || []
|
32
|
+
|
33
|
+
self.location = options[:location] || ProcedureLocation.new(type: options[:location_type],
|
34
|
+
details: options[:location_details])
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_admission_status(value)
|
38
|
+
self.class.admission_statuses.include?(value) ? value : 'UNKNOWN'
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_status(value)
|
42
|
+
self.class.statuses.include?(value) ? value : 'UNKNOWN'
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_transfer_status(value)
|
46
|
+
self.class.transfer_statuses.include?(value) ? value : 'UNKNOWN'
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_xml
|
50
|
+
builder = Builder::XmlMarkup.new
|
51
|
+
builder.Procedure do |p|
|
52
|
+
p.ProcedureID(procedure_id)
|
53
|
+
p.FacilityID(facility_id)
|
54
|
+
p << location.to_xml
|
55
|
+
p.ProcStartTime(start_time.strftime('%FT%T')) if start_time
|
56
|
+
p.ProcEndTime(end_time.strftime('%FT%T')) if end_time
|
57
|
+
p.AdmissionStatus(admission_status)
|
58
|
+
p.ProcStatus(status)
|
59
|
+
p.TransferStatus(transfer_status)
|
60
|
+
p.AdmissionDate(admission_date.strftime('%FT%T')) if admission_date
|
61
|
+
p.ProcedureNotes(notes) if notes
|
62
|
+
p.CPTSet do |c|
|
63
|
+
cpt_set.each do |cpt|
|
64
|
+
c << cpt.to_xml
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AQI
|
2
|
+
class ProcedureLocation
|
3
|
+
attr_accessor :type, :details
|
4
|
+
|
5
|
+
def self.types
|
6
|
+
["In-Patient", "Post In-Patient", "Out-Patient", "Post Out-Patient", "Obstetrics", "Surgery Center",
|
7
|
+
"Surgery Center Post Out-Patient", "Office", "Home", "Ambulatory Surgical Center", "Pharmacy",
|
8
|
+
"Skilled Nursing Facility", "Ambulance - Land", "Emergency Room Hospital", "Urgent Care Facility",
|
9
|
+
"Inpatient Psychiatric Facility", "School", "Custodial Care Facility",
|
10
|
+
"Residential Substance Abuse Treatment Facility", "Military Treatment Facility", "OTHER", "UNKNOWN"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
self.type = validate_type_code(options[:type])
|
15
|
+
self.details = options[:details]
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_type_code(code)
|
19
|
+
if self.class.types.include?(code)
|
20
|
+
code
|
21
|
+
else
|
22
|
+
'UNKNOWN'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_xml
|
27
|
+
builder = Builder::XmlMarkup.new
|
28
|
+
builder.ProcedureLocation do |pl|
|
29
|
+
pl.LocationType(type)
|
30
|
+
pl.LocationDetails(details)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AQI
|
2
|
+
class RecordHeader
|
3
|
+
attr_accessor :practice_id
|
4
|
+
|
5
|
+
def initialize(practice_id)
|
6
|
+
self.practice_id = practice_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_xml
|
10
|
+
builder = Builder::XmlMarkup.new
|
11
|
+
builder.RecordHeader do |rh|
|
12
|
+
rh.PracticeID(practice_id)
|
13
|
+
rh.CreatedBy('ProMedical')
|
14
|
+
rh.CreateDate(Time.now.strftime('%FT%T'))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/aqi/version.rb
ADDED
data/lib/aqi.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'date'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
require_relative "aqi/version"
|
6
|
+
require_relative "aqi/record_header"
|
7
|
+
require_relative "aqi/anesthesia_records"
|
8
|
+
require_relative "aqi/anesthesia_record"
|
9
|
+
require_relative "aqi/demographic"
|
10
|
+
require_relative "aqi/procedure_location"
|
11
|
+
require_relative "aqi/procedure"
|
12
|
+
require_relative "aqi/anesthesia_case"
|
13
|
+
require_relative "aqi/anesthesia_staff"
|
14
|
+
require_relative "aqi/ic_event"
|
15
|
+
require_relative "aqi/cpt"
|
16
|
+
require_relative "aqi/anesthesia_detail"
|
17
|
+
require_relative "aqi/intubation_detail"
|
18
|
+
require_relative "aqi/intake_output_set"
|
19
|
+
require_relative "aqi/pre_op"
|
20
|
+
require_relative "aqi/outcome_events"
|
21
|
+
require_relative "aqi/outcome"
|
22
|
+
|
23
|
+
module AQI; end
|
24
|
+
|
25
|
+
if __FILE__ == $0
|
26
|
+
class NullEncounter
|
27
|
+
Service = Struct.new(:start_time, :end_time, :performing_provider)
|
28
|
+
|
29
|
+
def date_of_birth; Time.now; end
|
30
|
+
def postal_code; "34476"; end
|
31
|
+
def state; "FL"; end
|
32
|
+
def city; "Ocala"; end
|
33
|
+
def gender; "M"; end
|
34
|
+
def encounter_id; 1; end
|
35
|
+
def location; "1003"; end
|
36
|
+
def location_name; "LROR"; end
|
37
|
+
def place_of_service; "LROR"; end
|
38
|
+
def services
|
39
|
+
[Service.new(Time.now, Time.now, "Dr. Perry Platypus")]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
puts AQI::RecordHeader.new("100000").to_xml
|
44
|
+
puts AQI::AnesthesiaRecord.new(NullEncounter.new).to_xml
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aqi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Jackson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-04 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Generates output based on the AQI schema.
|
15
|
+
email:
|
16
|
+
- robertj@promedicalinc.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- aqi.gemspec
|
27
|
+
- lib/aqi.rb
|
28
|
+
- lib/aqi/anesthesia_case.rb
|
29
|
+
- lib/aqi/anesthesia_detail.rb
|
30
|
+
- lib/aqi/anesthesia_record.rb
|
31
|
+
- lib/aqi/anesthesia_records.rb
|
32
|
+
- lib/aqi/anesthesia_staff.rb
|
33
|
+
- lib/aqi/cpt.rb
|
34
|
+
- lib/aqi/demographic.rb
|
35
|
+
- lib/aqi/ic_event.rb
|
36
|
+
- lib/aqi/intake_output_set.rb
|
37
|
+
- lib/aqi/intubation_detail.rb
|
38
|
+
- lib/aqi/outcome.rb
|
39
|
+
- lib/aqi/outcome_events.rb
|
40
|
+
- lib/aqi/pre_op.rb
|
41
|
+
- lib/aqi/procedure.rb
|
42
|
+
- lib/aqi/procedure_location.rb
|
43
|
+
- lib/aqi/record_header.rb
|
44
|
+
- lib/aqi/version.rb
|
45
|
+
homepage: https://github.com/promedical/aqi
|
46
|
+
licenses: []
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
none: false
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
none: false
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.24
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Generates output based on the AQI schema.
|
69
|
+
test_files: []
|
70
|
+
has_rdoc:
|