super_ehr 1.0.0
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 +7 -0
- data/lib/super_ehr.rb +518 -0
- metadata +45 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: adddf5fefce11f3bcd1124454e4fac6ece271e04
|
|
4
|
+
data.tar.gz: 552b22b0b6de40350469182a3337e9385c314f30
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 58aec116ab306abb82d69cd8b1be56e974f582899efe87deb299bac4058e0d5261e2b3201219722e31dd53d3bf5c4a8ad533ebd9286812c04e27c6880ff4f2da
|
|
7
|
+
data.tar.gz: e601918bc9195f1c1656cef29f613ea2e35d6ec4765fe09b49468c28f0301e4a3fdd1b2f128e1f6dcdb33475a74a403b15ec9b244e15f61d6a43af71065d54f3
|
data/lib/super_ehr.rb
ADDED
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'httparty'
|
|
4
|
+
require 'httmultiparty'
|
|
5
|
+
require 'builder'
|
|
6
|
+
require 'time'
|
|
7
|
+
|
|
8
|
+
module SuperEHR
|
|
9
|
+
|
|
10
|
+
def self.not_implemented(func)
|
|
11
|
+
puts "ERROR: #{func} not implemented"
|
|
12
|
+
raise NotImplementedError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class BaseEHR
|
|
16
|
+
|
|
17
|
+
### API SPECIFIC HOUSEKEEPING ###
|
|
18
|
+
|
|
19
|
+
# initialize necessary components
|
|
20
|
+
def initialize(default_params={})
|
|
21
|
+
@default_params = default_params
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def get_default_params
|
|
25
|
+
return {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_request_headers
|
|
29
|
+
return {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_request_body
|
|
33
|
+
return {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_request_url(endpoint)
|
|
37
|
+
return "/#{endpoint}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def refresh_token
|
|
41
|
+
SuperEHR.not_implemented(__callee__)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# make a HTTP request
|
|
45
|
+
def make_request(request_type, endpoint, request_params={}, use_default_params=true,
|
|
46
|
+
to_json=true)
|
|
47
|
+
|
|
48
|
+
if use_default_params
|
|
49
|
+
params = get_default_params
|
|
50
|
+
params = params.merge(request_params)
|
|
51
|
+
else
|
|
52
|
+
params = request_params
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
headers = get_request_headers
|
|
56
|
+
url = get_request_url(endpoint)
|
|
57
|
+
|
|
58
|
+
if request_type == "GET"
|
|
59
|
+
response = HTTParty.get(url, :query => params, :headers => headers)
|
|
60
|
+
elsif request_type == "POST"
|
|
61
|
+
if headers.key?("Content-Type") and headers["Content-Type"] == "application/json"
|
|
62
|
+
params = JSON.generate(params)
|
|
63
|
+
end
|
|
64
|
+
response = HTTParty.post(url, :body => params, :headers => headers)
|
|
65
|
+
else
|
|
66
|
+
puts "Request Type #{request_type} unsupported"
|
|
67
|
+
return
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if to_json
|
|
71
|
+
return JSON.parse(response.body)
|
|
72
|
+
else
|
|
73
|
+
return response.body
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### API CALLS ###
|
|
79
|
+
|
|
80
|
+
# Get details for a specific patient
|
|
81
|
+
def get_patient(patient_id)
|
|
82
|
+
SuperEHR.not_implemented(__callee__)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Gets a list of patients
|
|
86
|
+
def get_patients
|
|
87
|
+
SuperEHR.not_implemented(__callee__)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Get a list of patients changed since ts
|
|
91
|
+
def get_changed_patients(ts)
|
|
92
|
+
SuperEHR.not_implemented(__callee__)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Get a list of patients changed since ts
|
|
96
|
+
def get_changed_patients_ids(ts)
|
|
97
|
+
SuperEHR.not_implemented(__callee__)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Get patients scheduled for a specific day
|
|
101
|
+
def get_scheduled_patients(day)
|
|
102
|
+
SuperEHR.not_implemented(__callee__)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# upload a pdf
|
|
106
|
+
def upload_document(patient_id, filepath, description)
|
|
107
|
+
SuperEHR.not_implemented(__callee__)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class AllScriptsAPI < BaseEHR
|
|
112
|
+
|
|
113
|
+
### API SPECIFIC HOUSEKEEPING ###
|
|
114
|
+
|
|
115
|
+
def initialize(ehr_username, ehr_password='',
|
|
116
|
+
app_username, app_password, app_name,
|
|
117
|
+
using_touchworks)
|
|
118
|
+
|
|
119
|
+
# convert these to environment variables
|
|
120
|
+
@app_username = app_username
|
|
121
|
+
@app_password = app_password
|
|
122
|
+
@app_name = app_name
|
|
123
|
+
|
|
124
|
+
@ehr_username = ehr_username
|
|
125
|
+
# if not using touchworks ehr, then professional ehr is used
|
|
126
|
+
@using_touchworks = using_touchworks
|
|
127
|
+
|
|
128
|
+
if (using_touchworks)
|
|
129
|
+
base_url = "http://twlatestga.unitysandbox.com/unity/unityservice.svc"
|
|
130
|
+
else
|
|
131
|
+
base_url = "http://pro141ga.unitysandbox.com/Unity/unityservice.svc"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
@uri = URI(base_url)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def get_default_params
|
|
138
|
+
return {:Action => '', :AppUserID => @ehr_username, :Appname => @app_name,
|
|
139
|
+
:PatientID => '', :Token => refresh_token,
|
|
140
|
+
:Parameter1 => '', :Parameter2 => '', :Parameter3 => '',
|
|
141
|
+
:Parameter4 => '', :Parameter5 => '', :Parameter6 => '', :Data => ''}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def refresh_token
|
|
145
|
+
credentials = {:Username => @app_username, :Password => @app_password}
|
|
146
|
+
# last two params prevents usage of default params and output to json
|
|
147
|
+
return make_request("POST", "json/GetToken", credentials, false, false)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def get_request_headers
|
|
151
|
+
return { 'Content-Type' => 'application/json' }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def get_request_url(endpoint)
|
|
155
|
+
return "#{@uri}/#{endpoint}"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
### API CALLS ###
|
|
159
|
+
|
|
160
|
+
def get_patient(patient_id)
|
|
161
|
+
params = {:Action => 'GetPatient', :PatientID => patient_id}
|
|
162
|
+
response = make_request("POST", "json/MagicJson", params)[0]
|
|
163
|
+
patient_info = {}
|
|
164
|
+
if response.key?("getpatientinfo")
|
|
165
|
+
if not response["getpatientinfo"].empty?
|
|
166
|
+
patient_info = response["getpatientinfo"][0]
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
return patient_info
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def get_changed_patients(ts='')
|
|
173
|
+
patient_ids = get_changed_patients_ids(ts)
|
|
174
|
+
patients = []
|
|
175
|
+
for id in patient_ids
|
|
176
|
+
patients << get_patient(id)
|
|
177
|
+
end
|
|
178
|
+
return patients
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def get_changed_patients_ids(ts='')
|
|
182
|
+
params = {:Action => 'GetChangedPatients', :Parameter1 => ts}
|
|
183
|
+
response = make_request("POST", "json/MagicJson", params)[0]
|
|
184
|
+
patient_ids = []
|
|
185
|
+
if response.key?("getchangedpatientsinfo")
|
|
186
|
+
patient_ids = response["getchangedpatientsinfo"].map {|x| x["patientid"] }
|
|
187
|
+
end
|
|
188
|
+
return patient_ids
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def get_scheduled_patients(day)
|
|
192
|
+
params = {:Action => 'GetSchedule', :Parameter1 => day}
|
|
193
|
+
response = make_request("POST", "json/MagicJson", params)[0]
|
|
194
|
+
patients = []
|
|
195
|
+
if response.key?("getscheduleinfo")
|
|
196
|
+
if not response["getscheduleinfo"].empty?
|
|
197
|
+
for scheduled_patient in response["getscheduleinfo"]
|
|
198
|
+
patients << scheduled_patient
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
return patients
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
## UPLOAD PDF IMPLEMENTATION ##
|
|
206
|
+
|
|
207
|
+
def upload_document(patient_id, filepath, description)
|
|
208
|
+
|
|
209
|
+
patient = get_patient(patient_id)
|
|
210
|
+
first_name = patient["Firstname"]
|
|
211
|
+
last_name = patient["LastName"]
|
|
212
|
+
|
|
213
|
+
File.open(filepath, "r:UTF-8") do |file|
|
|
214
|
+
file_contents = file.read()
|
|
215
|
+
buffer = Base64.encode64(file_contents)
|
|
216
|
+
|
|
217
|
+
# first call to push the contents
|
|
218
|
+
save_pdf_xml = create_pdf_xml_params(first_name, last_name,
|
|
219
|
+
filepath, file.size, 0, "false", "", "0")
|
|
220
|
+
params = {:Action => 'SaveDocumentImage', :PatientID => patient_id,
|
|
221
|
+
:Parameter1 => save_pdf_xml, :Parameter6 => buffer}
|
|
222
|
+
out = make_request("POST", "json/MagicJson", params)
|
|
223
|
+
# second call to push file information and wrap up upload
|
|
224
|
+
doc_guid = out[0]["savedocumentimageinfo"][0]["documentVar"].to_s
|
|
225
|
+
save_pdf_xml = create_pdf_xml_params(first_name, last_name,
|
|
226
|
+
filepath, file.size, 0, "true", doc_guid, "0")
|
|
227
|
+
params = {:Action => 'SaveDocumentImage', :PatientID => patient_id,
|
|
228
|
+
:Parameter1 => save_pdf_xml, :Parameter6 => nil}
|
|
229
|
+
out = make_request("POST", "json/MagicJson", params)
|
|
230
|
+
return out
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# create XML parameters needed for upload_document
|
|
235
|
+
def create_pdf_xml_params(first_name, last_name, file_name, bytes_read,
|
|
236
|
+
offset, upload_done, docs_guid, encounter_id, organization_name="TouchWorks")
|
|
237
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
|
238
|
+
xml.doc do |b|
|
|
239
|
+
b.item :name => "documentCommand", :value => "i"
|
|
240
|
+
b.item :name => "documentType", :value => (@using_touchworks ? "sEKG" : "1")
|
|
241
|
+
b.item :name => "offset", :value => offset
|
|
242
|
+
b.item :name => "bytesRead", :value => bytes_read
|
|
243
|
+
b.item :name => "bDoneUpload", :value => upload_done
|
|
244
|
+
b.item :name => "documentVar", :value => docs_guid
|
|
245
|
+
b.item :name => "vendorFileName", :value => file_name
|
|
246
|
+
b.item :name => "ahsEncounterID", :value => 0
|
|
247
|
+
b.item :name => "ownerCode", :value => get_provider_entry_code.strip
|
|
248
|
+
b.item :name => "organizationName", :value => organization_name
|
|
249
|
+
b.item :name => "patientFirstName", :value => first_name
|
|
250
|
+
b.item :name => "patientLastName", :value => last_name
|
|
251
|
+
end
|
|
252
|
+
return xml.target!
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
private
|
|
256
|
+
|
|
257
|
+
# necessary to create the xml params for upload_document
|
|
258
|
+
def get_provider_entry_code()
|
|
259
|
+
params = {:Action => 'GetProvider', :Parameter2 => @ehr_username}
|
|
260
|
+
out = make_request("POST", "json/MagicJson", params)
|
|
261
|
+
return out[0]["getproviderinfo"][0]["EntryCode"]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def get_encounter(patient_id)
|
|
265
|
+
params = {:Action => 'GetEncounter', :PatientID => patient_id, :Parameter1 => "NonAppt",
|
|
266
|
+
:Parameter2 => Time.new.strftime("%b %d %Y %H:%M:%S"), :Parameter3 => true,
|
|
267
|
+
:Parameter4 => 'N'}
|
|
268
|
+
out = make_request("POST", "json/MagicJson", params)
|
|
269
|
+
return out[0]["getencounterinfo"][0]["EncounterID"]
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
class AthenaAPI < BaseEHR
|
|
274
|
+
|
|
275
|
+
### API SPECIFIC HOUSEKEEPING ###
|
|
276
|
+
|
|
277
|
+
def initialize(version, key, secret, practice_id)
|
|
278
|
+
@uri = URI.parse('https://api.athenahealth.com/')
|
|
279
|
+
@version = version
|
|
280
|
+
@key = key
|
|
281
|
+
@secret = secret
|
|
282
|
+
@practiceid = practice_id
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def get_request_headers
|
|
286
|
+
return { 'Authorization' => "Bearer #{refresh_token}" }
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def get_request_url(endpoint)
|
|
290
|
+
return "#{@uri}/#{@version}/#{@practiceid}/#{endpoint}"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def refresh_token
|
|
294
|
+
auth_paths = {
|
|
295
|
+
'vi' => 'oauth',
|
|
296
|
+
'preview1' => 'oauthpreview',
|
|
297
|
+
'openpreview1' => 'oauthopenpreview',
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
auth = {:username => @key, :password => @secret}
|
|
301
|
+
|
|
302
|
+
url = "#{@uri}/#{auth_paths[@version]}/token"
|
|
303
|
+
params = {:grant_type => "client_credentials"}
|
|
304
|
+
response = HTTParty.post(url, :body => params, :basic_auth => auth)
|
|
305
|
+
|
|
306
|
+
return response["access_token"]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
### API CALLS ###
|
|
311
|
+
|
|
312
|
+
def get_patient(patient_id)
|
|
313
|
+
response = make_request("GET", "patients/#{patient_id}", {})
|
|
314
|
+
patient_info = {}
|
|
315
|
+
if not response[0].empty?
|
|
316
|
+
patient_info = response[0]
|
|
317
|
+
end
|
|
318
|
+
return patient_info
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def get_changed_patients(ts='')
|
|
322
|
+
patient_ids = get_changed_patients_ids(ts)
|
|
323
|
+
patients = []
|
|
324
|
+
for id in patient_ids
|
|
325
|
+
patients << get_patient(id)
|
|
326
|
+
end
|
|
327
|
+
return patients
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# start_date needs to be in mm/dd/yyyy
|
|
331
|
+
# returns a list of patient ids that have been changed since start_date
|
|
332
|
+
def get_changed_patients_ids(start_date,
|
|
333
|
+
end_date=Time.new.strftime("%m/%d/%Y %H:%M:%S"))
|
|
334
|
+
subscribe = make_request("GET", "patients/changed/subscription", {})
|
|
335
|
+
if subscribe.has_key?("status") and subscribe["status"] == "ACTIVE"
|
|
336
|
+
response = make_request("GET", "patients/changed",
|
|
337
|
+
{ :ignorerestrictions => false,
|
|
338
|
+
:leaveunprocessed => false,
|
|
339
|
+
:showprocessedstartdatetime => "#{start_date} 00:00:00",
|
|
340
|
+
:showprocessedenddatetime => end_date })
|
|
341
|
+
patient_ids = []
|
|
342
|
+
if response.key?("patients")
|
|
343
|
+
patient_ids = response["patients"].map {|x| x["patientid"] }
|
|
344
|
+
end
|
|
345
|
+
return patient_ids
|
|
346
|
+
else
|
|
347
|
+
return nil
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def get_scheduled_patients(date, department_id=1)
|
|
352
|
+
response = make_request("GET", "appointments/booked",
|
|
353
|
+
{:departmentid => department_id, :startdate => date, :enddate => date})
|
|
354
|
+
patients = []
|
|
355
|
+
if not response["appointments"].empty?
|
|
356
|
+
for scheduled_patient in response["appointments"]
|
|
357
|
+
patients << scheduled_patient
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
return patients
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# might have issues if patient is in multiple departments
|
|
364
|
+
def upload_document(patient_id, filepath, description, department_id=-1)
|
|
365
|
+
endpoint = "patients/#{patient_id}/documents"
|
|
366
|
+
headers = { 'Authorization' => "Bearer #{refresh_token}" }
|
|
367
|
+
url = "#{@uri}/#{@version}/#{@practiceid}/#{endpoint}"
|
|
368
|
+
params = {
|
|
369
|
+
:departmentid => department_id != -1 ? department_id : get_patient(patient_id)["departmentid"],
|
|
370
|
+
:attachmentcontents => File.new(filepath),
|
|
371
|
+
:documentsubclass => "CLINICALDOCUMENT",
|
|
372
|
+
:autoclose => false,
|
|
373
|
+
:internalnote => description,
|
|
374
|
+
:actionnote => description }
|
|
375
|
+
|
|
376
|
+
response = HTTMultiParty.post(url, :body => params, :headers => headers)
|
|
377
|
+
return response
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
class DrChronoAPI < BaseEHR
|
|
383
|
+
|
|
384
|
+
### API SPECIFIC HOUSEKEEPING ###
|
|
385
|
+
|
|
386
|
+
def initialize(access_code, client_id, client_secret, redirect_uri)
|
|
387
|
+
@access_code = access_code
|
|
388
|
+
@client_id = client_id
|
|
389
|
+
@client_secret = client_secret
|
|
390
|
+
@redirect_uri = redirect_uri << '/' unless redirect_uri.end_with?('/')
|
|
391
|
+
@access_token = ''
|
|
392
|
+
@refresh_token = ''
|
|
393
|
+
@uri = URI.parse("https://drchrono.com")
|
|
394
|
+
if (access_code == '')
|
|
395
|
+
get_access_token
|
|
396
|
+
else
|
|
397
|
+
refresh_token
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def get_request_headers
|
|
402
|
+
return { 'Authorization' => "Bearer #{refresh_token}" }
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def get_request_url(endpoint)
|
|
406
|
+
return "#{@uri}/#{endpoint}"
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def refresh_token
|
|
410
|
+
if @refresh_token == ''
|
|
411
|
+
puts get_request_url("o/token")
|
|
412
|
+
puts @redirect_uri
|
|
413
|
+
response = HTTParty.post(get_request_url("o/token/"),
|
|
414
|
+
:body => {:code => @access_code,
|
|
415
|
+
:grant_type => "authorization_code",
|
|
416
|
+
:redirect_uri => @redirect_uri,
|
|
417
|
+
:client_id => @client_id,
|
|
418
|
+
:client_secret => @client_secret})
|
|
419
|
+
@refresh_token = response["refresh_token"]
|
|
420
|
+
@access_token = response["access_token"]
|
|
421
|
+
return response["access_token"]
|
|
422
|
+
else
|
|
423
|
+
response = HTTParty.post(get_request_url("o/token/"),
|
|
424
|
+
:body => {:refresh_token => @refresh_token,
|
|
425
|
+
:grant_type => "refresh_token",
|
|
426
|
+
:redirect_uri => @redirect_uri,
|
|
427
|
+
:client_id => @client_id,
|
|
428
|
+
:client_secret => @client_secret})
|
|
429
|
+
@refresh_token = response["refresh_token"]
|
|
430
|
+
@access_token = response["access_token"]
|
|
431
|
+
return response["access_token"]
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def chrono_request(endpoint, params={})
|
|
437
|
+
result = []
|
|
438
|
+
while endpoint
|
|
439
|
+
data = make_request("GET", endpoint, params)
|
|
440
|
+
if data["results"]
|
|
441
|
+
result = result | data["results"]
|
|
442
|
+
end
|
|
443
|
+
endpoint = data["next"]
|
|
444
|
+
end
|
|
445
|
+
return result
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
### API CALLS ###
|
|
449
|
+
|
|
450
|
+
# Not efficient
|
|
451
|
+
# Get the patient using patient id from our database
|
|
452
|
+
def get_patient(patient_id)
|
|
453
|
+
patients = get_patients()
|
|
454
|
+
for patient in patients
|
|
455
|
+
if patient["id"] == patient_id
|
|
456
|
+
return patient
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
return nil
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def get_patients(params={})
|
|
463
|
+
patient_url = 'api/patients'
|
|
464
|
+
return chrono_request(patient_url, params)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def get_changed_patients(ts)
|
|
468
|
+
date = ts.gsub(/\//, '-')
|
|
469
|
+
date = Date.strptime(date, '%m-%d-%Y')
|
|
470
|
+
return get_patients({:since => date.iso8601})
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def get_changed_patients_ids(ts)
|
|
474
|
+
patients = get_changed_patients(ts)
|
|
475
|
+
ids = []
|
|
476
|
+
for patient in patients
|
|
477
|
+
ids << patient["id"]
|
|
478
|
+
end
|
|
479
|
+
return ids
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def get_scheduled_patients(day='')
|
|
483
|
+
url = 'api/appointments'
|
|
484
|
+
return chrono_request(url, {:date => day.gsub(/\//, '-')})
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def upload_document(patient_id, filepath, description)
|
|
488
|
+
url = get_request_url("api/documents")
|
|
489
|
+
headers = get_request_headers
|
|
490
|
+
params = {
|
|
491
|
+
:doctor => /\/api\/doctors\/.*/.match(get_patient(patient_id)["doctor"]),
|
|
492
|
+
:patient => "/api/patients/#{patient_id}",
|
|
493
|
+
:description => description,
|
|
494
|
+
:date => Time.now.strftime("%Y-%m-%d") << " 00:00:00",
|
|
495
|
+
:document => File.new(filepath)
|
|
496
|
+
}
|
|
497
|
+
response = HTTMultiParty.post(url, :body => params, :headers => headers)
|
|
498
|
+
return response
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def self.allscripts(ehr_username, ehr_password,
|
|
504
|
+
app_username, app_password, app_name,
|
|
505
|
+
using_touchworks)
|
|
506
|
+
return AllScriptsAPI.new(ehr_username, ehr_password,
|
|
507
|
+
app_username, app_password, app_name,
|
|
508
|
+
using_touchworks)
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
def self.athena(version, key, secret, practice_id)
|
|
512
|
+
return AthenaAPI.new(version, key, secret, practice_id)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def self.drchrono(access_code, client_id, client_secret, redirect_uri)
|
|
516
|
+
return DrChronoAPI.new(access_code, client_id, client_secret, redirect_uri)
|
|
517
|
+
end
|
|
518
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: super_ehr
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Brian Su
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-04-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: This project generalizes EHR integrations with various EHR vendors. Currently
|
|
14
|
+
supports Allscripts, Athena, and DrChrono.
|
|
15
|
+
email: brian@bsu.me
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- lib/super_ehr.rb
|
|
21
|
+
homepage: http://rubygems.org/gems/super_ehr
|
|
22
|
+
licenses:
|
|
23
|
+
- MIT
|
|
24
|
+
metadata: {}
|
|
25
|
+
post_install_message:
|
|
26
|
+
rdoc_options: []
|
|
27
|
+
require_paths:
|
|
28
|
+
- lib
|
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 2.4.3
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 4
|
|
44
|
+
summary: Integrate with various EHR APIs seamlessly.
|
|
45
|
+
test_files: []
|