claimer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 64dfdaa3088774f8d40ecf59223401c3d64f7951
4
+ data.tar.gz: 1c1f862ad742a4880b55aed1a9eb325c4a7b281b
5
+ SHA512:
6
+ metadata.gz: febe66c07a25f60502ee6841b7407403d7dc93e55cbd62257db600a3fbfb028b5658061c29e1c2a1c6f2abecc7f9cf3557db77517de4d80664fd14ccfeb44ffd
7
+ data.tar.gz: c2bc3afe86299d8ed294e374910684b89742e3cbd39592b0c0695b09d1c4fa845632f9ecbfe2a1a43659eda664afdefd56b1df4a884c4a7fc5393debd1ebb0b5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 The Well Inspired Ventures, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Brady Bouchard
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,4 @@
1
+ claimer
2
+ =======
3
+
4
+ Ruby library for Automated Claim Submissions to Canadian Provincial Medical Service Branches.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/claimer.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Claimer
2
+
3
+ autoload :SK, 'claimer/gateways/sk'
4
+
5
+ end
6
+
7
+ require 'claimer/version'
8
+ require 'claimer/gateway'
9
+ require 'claimer/record'
@@ -0,0 +1,4 @@
1
+ module Claimer
2
+ class Gateway
3
+ end
4
+ end
@@ -0,0 +1,154 @@
1
+ module Claimer
2
+ class SK < Gateway
3
+
4
+ attr_accessor :records, :first_claim_number
5
+
6
+ def initialize(values = {})
7
+ self.records = []
8
+ self.first_claim_number = 10000
9
+ end
10
+
11
+ def add_record(*args)
12
+ self.records << Claimer::Record.new(*args)
13
+ end
14
+
15
+ def finalize!
16
+ collate_records
17
+ end
18
+
19
+ def push!
20
+ finalize!
21
+ end
22
+
23
+ private
24
+
25
+ def header_record(selected_records)
26
+ [
27
+ '10', # Record type number
28
+ selected_records.first.doctor_number.to_s.rjust(4, '0'),
29
+ '000000', # Filler
30
+ selected_records.first.clinic_number.to_s.rjust(3, '0'),
31
+ selected_records.first.doctor_name.to_s[0..24].rjust(25, '0').upcase,
32
+ selected_records.first.clinic_address.to_s[0..24].rjust(25, '0').upcase,
33
+ selected_records.first.clinic_city_and_prov.to_s[0..24].rjust(25, '0').upcase,
34
+ selected_records.first.clinic_postal_code.to_s[0..24].rjust(25, '0').upcase,
35
+ '8', # Submission type: By Internet.
36
+ '' # Practitioner billing.
37
+ ].join('')
38
+ end
39
+
40
+ def trailer_record(selected_records)
41
+ [
42
+ '90', # Record type number
43
+ selected_records.first.doctor_number.to_s.rjust(4, '0'),
44
+ '999999', # Filler
45
+ selected_records.count.to_s.rjust(5, '0'),
46
+ selected_records.reject{ |r| r.comments.nil? || r.comments.length == 0 }.count.to_s.rjust(5, '0'),
47
+ selected_records.count.to_s.rjust(7, '0'),
48
+ '69' # Filler
49
+ ].join('')
50
+ end
51
+
52
+ def record_format(record)
53
+ if record.in_hospital
54
+ hospital_record_format(record)
55
+ else
56
+ visit_record_format(record)
57
+ end
58
+ end
59
+
60
+ def hospital_record_format(record)
61
+ [
62
+ '57', # Record type number
63
+ record.doctor_number.to_s.rjust(4, '0'),
64
+ record.claim_number.to_s[0..4],
65
+ '0', # Placeholder for claim sequence number.
66
+ record.hsn.to_s[0..8],
67
+ record.dob.strftime('%m%y'),
68
+ record.sex.to_s.upcase,
69
+ "#{record.last_name} #{record.first_name}"[0..24].ljust(25),
70
+ record.icd9.to_s[0..2].rjust(3, '0'),
71
+ record.referring_doctor_number.rjust(4),
72
+ record.date_of_service.strftime('%d%m%y'),
73
+ record.number_of_units.to_s.rjust(2, '0'),
74
+ '1', # Location of service
75
+ record.fee_code.to_s.rjust(4, '0'),
76
+ record.fee.to_s.gsub('.','').gsub('$','').rjust(6, '0'),
77
+ '1', # Physician code.
78
+ '8', # Submission by internet.
79
+ ' ' * 19 # Filler.
80
+ ].join('')
81
+ end
82
+
83
+ def visit_record_format(record)
84
+ [
85
+ '50', # Record type number
86
+ record.doctor_number.to_s.rjust(4, '0'),
87
+ record.claim_number.to_s[0..4],
88
+ '0', # Placeholder for claim sequence number.
89
+ record.hsn.to_s[0..8],
90
+ record.dob.strftime('%m%y'),
91
+ record.sex.to_s.upcase,
92
+ "#{record.last_name} #{record.first_name}"[0..24].ljust(25),
93
+ record.icd9.to_s[0..2].rjust(3, '0'),
94
+ record.referring_doctor_number.rjust(4),
95
+ record.date_of_service.strftime('%d%m%y'),
96
+ record.number_of_units.to_s.rjust(2, '0'),
97
+ '1', # Location of service
98
+ record.fee_code.to_s.rjust(4, '0'),
99
+ record.fee.to_s.gsub('.','').gsub('$','').rjust(6, '0'),
100
+ '1', # Physician code.
101
+ '8', # Submission by internet.
102
+ ' ' * 19 # Filler.
103
+ ].join('')
104
+ end
105
+
106
+ def comment_format(record)
107
+ return nil if record.comments.nil? || record.comments.length == 0
108
+ [
109
+ '60', # Record type number
110
+ record.doctor_number.to_s.rjust(4, '0'),
111
+ record.claim_number.to_s[0..4],
112
+ '0', # Placeholder for claim sequence number.
113
+ record.hsn.to_s[0..8],
114
+ record.comments.to_s[0..76].upcase # Comments.
115
+ ].join('')
116
+ end
117
+
118
+ # Claim numbers are assigned sequentially starting at first_claim_number.
119
+ # Claim sequence numbers are all 0 - this part of the API (if you can call it an API)
120
+ # hasn't been implemented yet.
121
+ def assign_claim_numbers
122
+ c = self.first_claim_number
123
+ self.records.each_with_index do |r|
124
+ r.claim_number ||= c + r - 1
125
+ r.claim_sequence_number ||= 0
126
+ end
127
+ end
128
+
129
+ # MSB requires records to be sent in clinic-doctor sets.
130
+ def collate_records
131
+
132
+ assign_claim_numbers
133
+
134
+ doctor_numbers = self.records.map{ |r| r.doctor_number }.uniq
135
+ clinic_numbers = self.records.map{ |r| r.clinic_number }.uniq
136
+
137
+ clinic_numbers.map do |cn|
138
+ doctor_numbers.map do |dn|
139
+ selected_records = self.records.select{ |r| r.doctor_number == dn && r.clinic_number == cn }
140
+ [
141
+ header_record(selected_records),
142
+ selected_records.map do |r|
143
+ formatted_result = record_format(r)
144
+ formatted_comment = comment_format(r)
145
+ [ formatted_result, formatted_comment ].compact.join("\n")
146
+ end.join("\n"),
147
+ trailer_record(selected_records)
148
+ ].join("\n")
149
+ end
150
+ end.flatten.join("\n")
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,36 @@
1
+ module Claimer
2
+ class Record
3
+
4
+ attr_accessor :doctor_number, :referring_doctor_number, :doctor_name, :clinic_number,
5
+ :clinic_address, :clinic_city_and_prov, :clinic_postal_code, :hsn, :dob,
6
+ :sex, :first_name, :last_name, :icd9, :date_of_service, :end_date_of_service,
7
+ :number_of_units, :fee, :fee_code, :comments, :claim_number,
8
+ :claim_sequence_number, :in_hospital
9
+
10
+ def initialize(values = {})
11
+ self.doctor_number = values[:doctor_number]
12
+ self.referring_doctor_number = values[:referring_doctor_number] || ''
13
+ self.doctor_name = values[:doctor_name]
14
+ self.clinic_number = values[:clinic_number]
15
+ self.clinic_address = values[:clinic_address]
16
+ self.clinic_city_and_prov = values[:clinic_city_and_prov]
17
+ self.clinic_postal_code = values[:clinic_postal_code]
18
+ self.hsn = values[:hsn]
19
+ self.dob = values[:dob]
20
+ self.sex = values[:sex]
21
+ self.first_name = values[:first_name]
22
+ self.last_name = values[:last_name]
23
+ self.icd9 = values[:icd9]
24
+ self.date_of_service = values[:date_of_service]
25
+ self.end_date_of_service = values[:end_date_of_service]
26
+ self.number_of_units = values[:number_of_units]
27
+ self.fee = values[:fee]
28
+ self.fee_code = values[:fee_code]
29
+ self.comments = values[:comments]
30
+ self.claim_number = values[:claim_number] || 0
31
+ self.claim_sequence_number = values[:claim_sequence_number] || 0
32
+ self.in_hospital = values[:in_hospital] || false
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Claimer
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require_relative 'test_submission'
3
+
4
+ describe Claimer::SK do
5
+ before(:all) do
6
+ require 'csv'
7
+ @gateway = Claimer::SK.new
8
+ CSV.foreach(File.expand_path('./sk_test.csv', File.dirname(__FILE__)), :headers => true) do |csv|
9
+ @gateway.add_record(
10
+ :hsn => csv['hsn'],
11
+ :sex => csv['sex'],
12
+ :dob => parse_dob(csv['dob']),
13
+ :last_name => csv['name'].split(',')[0].strip,
14
+ :first_name => csv['name'].split(',')[1].strip,
15
+ :claim_number => csv['claim_number'],
16
+ :claim_sequence_number => csv['claim_sequence_number'],
17
+ :icd9 => csv['icd9'],
18
+ :date_of_service => parse_date(csv['start_date']),
19
+ :end_date_of_service => parse_date(csv['end_date']),
20
+ :number_of_units => csv['visits_or_units'],
21
+ :fee_code => csv['fee_code'],
22
+ :fee => (csv['fee'].to_f * 100).round,
23
+ :referring_doctor => csv['referring_doctor'],
24
+ :location => csv['location'],
25
+ :comments => csv['comment'],
26
+ :doctor_number => 9800,
27
+ :doctor_name => 'General Practice',
28
+ :clinic_number => 000
29
+ )
30
+ end
31
+ end
32
+
33
+ it 'validates test data against known good submission' do
34
+ expect(@gateway.finalize!).to eq(KNOWN_GOOD_SUBMISSION)
35
+ end
36
+
37
+ def parse_date(d)
38
+ return d unless d.is_a?(String)
39
+ return nil if d.nil?
40
+ Date.strptime(d.rjust(6, '0'), '%d%m%y')
41
+ end
42
+
43
+ def parse_dob(d)
44
+ return d unless d.is_a?(String)
45
+ return nil if d.nil?
46
+ Date.strptime(d.rjust(4, '0'), '%m%y')
47
+ end
48
+ end
@@ -0,0 +1 @@
1
+ hsn,sex,dob,name,claim_number,claim_sequence_number,icd9,start_date,end_date,visits_or_units,fee_code,fee,referring_doctor,location,comment
@@ -0,0 +1,21 @@
1
+ KNOWN_GOOD_SUBMISSION = %/109800000000000000000000GENERAL|PRACTICE0000000000000000000000000000000000000000000000000000000000000000000000000008
2
+ 509800100860621030081039FSAMPSON|MARY|||||||||||||737||||180600011003B00390018|||||||||||||||||||
3
+ 509800100870880060000669MSAMPSON|JOHN|||||||||||||078||||180600011005B00192518|||||||||||||||||||
4
+ 509800100880730700090874MGREEN|DAVID||||||||||||||535||||190600011003B00390018|||||||||||||||||||
5
+ 509800100890721650140514FHOERDT|OLGA||||||||||||||207||||190600011009L00600018|||||||||||||||||||
6
+ 509800100890721650140514FHOERDT|OLGA||||||||||||||207||||190600011817A00229018|||||||||||||||||||
7
+ 509800100900700030091161MBEACH|ANDY|||||||||||||||300||||210600011003B00390018|||||||||||||||||||
8
+ 509800100910620340061260MKIPLING|BRIAN||||||||||||729||||210600011005D00192518|||||||||||||||||||
9
+ 509800100920731020080261FFISHER|SUSAN|||||||||||||550||||190600011009L00600018|||||||||||||||||||
10
+ 509800100930620340061260MKIPLING|BRIAN||||||||||||214||||210600011362L01000018|||||||||||||||||||
11
+ 60980010093062034006THIS|IS|A|COMMENT|THAT|APPLIES|TO|THE|ABOVE|LINE
12
+ 509800100940722150110261FMYERS|SUSAN||||||||||||||221||||210600011005B00192518|||||||||||||||||||
13
+ 509800100950610010151039FANDERS|MARY||||||||||||||207||||180600011011B00235018|||||||||||||||||||
14
+ 509800100960621000090737MANDERS|FRANCIS|||||||||||490||||190600011005B00192518|||||||||||||||||||
15
+ 509800100970620040000667MANDERS|JOHN||||||||||||||289||||140600011009B00470018|||||||||||||||||||
16
+ 509800100980620040000667MANDERS|JOHN||||||||||||||289||||140600011025B00207018|||||||||||||||||||
17
+ 509800100990722610050737FPLUE|PENNY|||||||||||||||300||||210600011005B00192518|||||||||||||||||||
18
+ 509800101000600020001039FEDWARDS|MARY|||||||||||||194||||210600011005B00192518|||||||||||||||||||
19
+ 509800101010721710571037FMACK|MARY||||||||||||||||786||||210600011005B00192518|||||||||||||||||||
20
+ 509800101020621050190423MCRANE|REG||||||||||||||||V25||||210600011190R01630018|||||||||||||||||||
21
+ 9098009999990001800001000001869/.gsub('|',' ')
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'claimer'
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: claimer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brady Bouchard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: A Ruby library for preparing, formatting and submitting claim submissions
56
+ for medicare services provided by physicians, segmented by province in Canada.
57
+ email:
58
+ - brady@thewellinspired.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/claimer.rb
68
+ - lib/claimer/gateway.rb
69
+ - lib/claimer/gateways/sk.rb
70
+ - lib/claimer/record.rb
71
+ - lib/claimer/version.rb
72
+ - spec/provinces/sk_spec.rb
73
+ - spec/provinces/sk_test.csv
74
+ - spec/provinces/test_submission.rb
75
+ - spec/spec_helper.rb
76
+ homepage: https://github.com/bouchard/claimer
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.2.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Ruby library for automated claim submissions to Canadian Provincial Medical
100
+ Service Branches.
101
+ test_files:
102
+ - spec/provinces/sk_spec.rb
103
+ - spec/provinces/sk_test.csv
104
+ - spec/provinces/test_submission.rb
105
+ - spec/spec_helper.rb