nppes 0.1.2
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 +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +140 -0
- data/Rakefile +10 -0
- data/lib/generators/active_record/base_npi_data.rb +33 -0
- data/lib/generators/active_record/license.rb +20 -0
- data/lib/generators/active_record/update_check.rb +14 -0
- data/lib/generators/nppes/install_generator.rb +42 -0
- data/lib/generators/templates/delayed_jobs.rb +7 -0
- data/lib/generators/templates/nppes.rb +17 -0
- data/lib/nppes.rb +60 -0
- data/lib/nppes/jobs.rb +3 -0
- data/lib/nppes/jobs/initer_job.rb +9 -0
- data/lib/nppes/jobs/searcher_job.rb +29 -0
- data/lib/nppes/jobs/updater_job.rb +13 -0
- data/lib/nppes/models.rb +3 -0
- data/lib/nppes/np_identifier.rb +8 -0
- data/lib/nppes/np_license.rb +5 -0
- data/lib/nppes/np_update_check.rb +7 -0
- data/lib/nppes/railtie.rb +12 -0
- data/lib/nppes/tasks/nppes.rake +54 -0
- data/lib/nppes/update_pack.rb +4 -0
- data/lib/nppes/update_pack/base.rb +18 -0
- data/lib/nppes/update_pack/data.rb +39 -0
- data/lib/nppes/update_pack/header.rb +114 -0
- data/lib/nppes/update_pack/pack.rb +89 -0
- data/lib/nppes/update_pack/required_fields.rb +86 -0
- data/lib/nppes/version.rb +3 -0
- data/nppes.gemspec +29 -0
- data/spec/delayed_jobs_spec.rb +14 -0
- data/spec/parse_spec.rb +7 -0
- data/spec/spec_helper.rb +22 -0
- metadata +184 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jenua Boiko
|
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,140 @@
|
|
1
|
+
# EmailTemplate
|
2
|
+
|
3
|
+
Allows your users to edit e-mail templates.
|
4
|
+
With Devise and Active Admin support (but you don't need them to start using email_template).
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'email_template'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
```sh
|
17
|
+
$ bundle
|
18
|
+
```
|
19
|
+
|
20
|
+
Or just:
|
21
|
+
|
22
|
+
```sh
|
23
|
+
$ gem install email_template
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Run installer:
|
29
|
+
|
30
|
+
```sh
|
31
|
+
$ rails g email_template:install
|
32
|
+
```
|
33
|
+
|
34
|
+
In order to use Devise templates you need to install devise wrapper:
|
35
|
+
|
36
|
+
```sh
|
37
|
+
$ rails g email_template:devise_install
|
38
|
+
```
|
39
|
+
|
40
|
+
Then generate common devise templates for a specified scope:
|
41
|
+
|
42
|
+
```sh
|
43
|
+
$ rails g email_template:devise_templates <devise_scope>
|
44
|
+
```
|
45
|
+
|
46
|
+
This generator produces email templates with the names:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
<devise_scope>_mailer:confirmation_instructions
|
50
|
+
<devise_scope>_mailer:reset_password_instructions
|
51
|
+
<devise_scope>_mailer:unlock_instructions
|
52
|
+
```
|
53
|
+
|
54
|
+
Run:
|
55
|
+
|
56
|
+
```sh
|
57
|
+
$ rake db:migrate
|
58
|
+
```
|
59
|
+
|
60
|
+
You can configure email_template at
|
61
|
+
|
62
|
+
config/initializers/email_template.rb
|
63
|
+
|
64
|
+
Pull template to the base :
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
MailTemplate.create(name: "template unique name",
|
68
|
+
subject: "Join request confirmation",
|
69
|
+
classes: ["activity_partner"],
|
70
|
+
body:
|
71
|
+
<<-TEXT
|
72
|
+
Dear \#{activity_partner.full_name} ...
|
73
|
+
....
|
74
|
+
TEXT
|
75
|
+
)
|
76
|
+
```
|
77
|
+
|
78
|
+
In Mailer:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class ActivityPartnerMailer < TemplateSendMailer
|
82
|
+
def join_confirmation_self(activity_partner)
|
83
|
+
#send_mail(template_name, mail_params = {}, template_params = {})
|
84
|
+
send_mail("template unique name", {to: "user@example.com"}, {activity_partner_: activity_partner})
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
## Configuration
|
90
|
+
If you need adding some model method to token list need create in model alias with prefix,
|
91
|
+
which you set in config(by default is 'et_').
|
92
|
+
|
93
|
+
For example if you need add method 'full_name' for 'activity_partner' to token list you need do next:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class ActivityPartner < ActiveRecord::Base
|
97
|
+
def full_name
|
98
|
+
[self.first_name, self.last_name].join(' ')
|
99
|
+
end
|
100
|
+
|
101
|
+
alias et_full_name full_name
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
|
106
|
+
## Customization
|
107
|
+
|
108
|
+
In case you need additional customization :
|
109
|
+
|
110
|
+
In Mailer:
|
111
|
+
Simply add 'template_path' and 'template_name'
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
class MyMailer < TemplateSendMailer
|
115
|
+
|
116
|
+
def result(tree)
|
117
|
+
send_mail('MyMailer:result',
|
118
|
+
{
|
119
|
+
to: my_email,
|
120
|
+
template_path: 'mailers',
|
121
|
+
template_name: 'mail'
|
122
|
+
}, {tree: tree})
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
In View:
|
128
|
+
In view you will have compiled template in @data variable
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
= @data.html_safe
|
132
|
+
```
|
133
|
+
|
134
|
+
## Contributing
|
135
|
+
|
136
|
+
1. Fork it
|
137
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
138
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
139
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
140
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class AddNppesTable < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :np_identifiers do |t|
|
4
|
+
t.integer :npi
|
5
|
+
t.integer :owner_id
|
6
|
+
t.string :owner_type
|
7
|
+
|
8
|
+
t.string :npi_deactivation_reason_code, :limit => 2
|
9
|
+
t.date :npi_deactivation_date
|
10
|
+
t.date :npi_reactivation_date
|
11
|
+
|
12
|
+
t.string :first_name, :limit => 50
|
13
|
+
t.string :middle_name, :limit => 50
|
14
|
+
t.string :last_name, :limit => 50
|
15
|
+
t.string :prefix, :limit => 5
|
16
|
+
t.string :suffix, :limit => 5
|
17
|
+
|
18
|
+
t.string :gender_code, :limit => 1
|
19
|
+
t.string :entity_type_code, :limit => 1
|
20
|
+
|
21
|
+
t.date :last_update_date
|
22
|
+
|
23
|
+
t.timestamps
|
24
|
+
end
|
25
|
+
|
26
|
+
add_index(:np_identifiers, [:npi], {:name => 'np_identifiers_npi'})
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.down
|
30
|
+
#remove_index :np_identifiers, :name => 'np_identifiers_npi'
|
31
|
+
drop_table :np_identifiers
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class AddLicenseTable < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :np_licenses do |t|
|
4
|
+
t.integer :np_identifier_id
|
5
|
+
|
6
|
+
(1..15).each do |i|
|
7
|
+
t.string "taxonomy_code_#{i}", :limit => 10
|
8
|
+
t.string "license_number_#{i}", :limit => 10
|
9
|
+
t.string "license_number_state_code_#{i}", :limit => 2
|
10
|
+
t.string "healthcare_taxonomy_switch_#{i}", :limit => 1
|
11
|
+
end
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :np_licenses
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Nppes
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
include ::Rails::Generators::Migration
|
5
|
+
|
6
|
+
def self.next_migration_number(dirname)
|
7
|
+
Time.now.strftime('%Y%m%d%H%M%S')
|
8
|
+
end
|
9
|
+
|
10
|
+
source_root File.expand_path('../../', __FILE__)
|
11
|
+
|
12
|
+
desc 'Creates initializer and migration.'
|
13
|
+
def copy_initializer
|
14
|
+
migration_template(
|
15
|
+
'active_record/base_npi_data.rb',
|
16
|
+
migrate_path('add_nppes_table.rb')
|
17
|
+
)
|
18
|
+
sleep(1)
|
19
|
+
migration_template(
|
20
|
+
'active_record/update_check.rb',
|
21
|
+
migrate_path('add_update_check_table.rb')
|
22
|
+
)
|
23
|
+
|
24
|
+
#sleep(1)
|
25
|
+
#migration_template(
|
26
|
+
# 'active_record/license.rb',
|
27
|
+
# migrate_path('add_license_table.rb')
|
28
|
+
#)
|
29
|
+
|
30
|
+
template 'templates/nppes.rb', 'config/initializers/nppes_settings.rb'
|
31
|
+
generate 'delayed_job:active_record'
|
32
|
+
template 'templates/delayed_jobs.rb', 'config/initializers/delayed_jobs.rb'
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def migrate_path(name='')
|
38
|
+
File.join('db', 'migrate', name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Delayed::Worker.destroy_failed_jobs = false
|
2
|
+
Delayed::Worker.sleep_delay = 1
|
3
|
+
Delayed::Worker.max_attempts = 100
|
4
|
+
Delayed::Worker.max_run_time = 20.hours
|
5
|
+
Delayed::Worker.read_ahead = 10
|
6
|
+
Delayed::Worker.default_queue_name = 'default'
|
7
|
+
Delayed::Worker.delay_jobs = !Rails.env.test?
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Nppes.setup do |config|
|
2
|
+
|
3
|
+
#config.updates_url
|
4
|
+
#default updates_url = 'http://nppes.viva-it.com/NPI_Files.html'
|
5
|
+
|
6
|
+
#config.initiate_signature
|
7
|
+
#default initiate_signature = /.+\/NPPES_Data_Dissemination_\w+_\d+\.zip/
|
8
|
+
|
9
|
+
#config.weekly_signature
|
10
|
+
#default weekly_signature = /.+\/NPPES_Data_Dissemination_\d+_\d+_Weekly\.zip/
|
11
|
+
|
12
|
+
#config.monthly_signature
|
13
|
+
#default monthly_signature = /.+\/NPPES_Deactivated_NPI_Report_\d+.zip/
|
14
|
+
|
15
|
+
#config.weekly
|
16
|
+
#default weekly = true
|
17
|
+
end
|
data/lib/nppes.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'delayed_job'
|
2
|
+
require 'nppes/models'
|
3
|
+
require 'nppes/jobs'
|
4
|
+
require 'nppes/update_pack'
|
5
|
+
require 'nppes/railtie' if defined?(Rails)
|
6
|
+
|
7
|
+
module Nppes
|
8
|
+
mattr_accessor :updates_url
|
9
|
+
self.updates_url = 'http://nppes.viva-it.com/NPI_Files.html'
|
10
|
+
|
11
|
+
mattr_accessor :initiate_signature
|
12
|
+
self.initiate_signature = /.+\/NPPES_Data_Dissemination_\w+_\d+\.zip/
|
13
|
+
|
14
|
+
mattr_accessor :weekly_signature
|
15
|
+
self.weekly_signature = /.+\/NPPES_Data_Dissemination_\d+_\d+_Weekly\.zip/
|
16
|
+
|
17
|
+
mattr_accessor :monthly_signature
|
18
|
+
self.monthly_signature = /.+\/NPPES_Deactivated_NPI_Report_\d+.zip/
|
19
|
+
|
20
|
+
mattr_accessor :weekly
|
21
|
+
self.weekly = true
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def logger
|
25
|
+
@@logger ||= Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup
|
29
|
+
yield self
|
30
|
+
end
|
31
|
+
|
32
|
+
def update
|
33
|
+
UpdatePack::Pack.check_updates
|
34
|
+
end
|
35
|
+
|
36
|
+
def background_update(continious = false)
|
37
|
+
UpdatePack::Pack.background_check_updates(continious)
|
38
|
+
end
|
39
|
+
|
40
|
+
def init
|
41
|
+
UpdatePack::Pack.init_base
|
42
|
+
end
|
43
|
+
|
44
|
+
def background_init
|
45
|
+
UpdatePack::Pack.background_init_base
|
46
|
+
end
|
47
|
+
|
48
|
+
def init_by_file(zip_file_name)
|
49
|
+
UpdatePack::Pack.proceed(zip_file_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_npi?(npi)
|
53
|
+
Nppes::NpIdentifier.where(npi: npi).present?
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_time_period
|
57
|
+
weekly ? 8.days.to_i : 32.days.to_i
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/nppes/jobs.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Nppes
|
2
|
+
module Jobs
|
3
|
+
class SearcherJob < Struct.new(:period)
|
4
|
+
def perform
|
5
|
+
UpdatePack::Pack.check_updates
|
6
|
+
end
|
7
|
+
# not tested
|
8
|
+
def reschedule_at(time, attempts)
|
9
|
+
Nppes.logger.warn 'Rescheduling'
|
10
|
+
time + 2.hours
|
11
|
+
end
|
12
|
+
|
13
|
+
def after(job)
|
14
|
+
if period
|
15
|
+
Nppes.logger.warn 'Create next update job'
|
16
|
+
Delayed::Job.enqueue(Nppes::Jobs::SearcherJob.new(period), 0, Time.now + period)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#def error(job, error)
|
21
|
+
# #self.class.messages << "error: #{error.class}"
|
22
|
+
#end
|
23
|
+
#
|
24
|
+
#def failure(job)
|
25
|
+
# #self.class.messages << 'failure'
|
26
|
+
#end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/nppes/models.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'nppes'
|
3
|
+
|
4
|
+
namespace :nppes do
|
5
|
+
def already_run?
|
6
|
+
`ps aux | grep delayed_job | awk '{print $11}'`.lines.detect {|line| line == "delayed_job\n"}.present?
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_pid?
|
10
|
+
Dir[Rails.root.join('tmp', 'pids','delayed_job*.pid')].present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_env
|
14
|
+
unless already_run?
|
15
|
+
STDOUT << "Run env ...\n"
|
16
|
+
Rake::Task['nppes:start_background_env'].invoke
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Finish all background processes'
|
21
|
+
task :stop_all do
|
22
|
+
`kill -9 $(ps aux | less | grep delayed_job | awk '{print $2}')`
|
23
|
+
Dir[Rails.root.join('tmp', 'pids','delayed_job*.pid')].each {|file| File.delete file}
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Start background env. Please specify RAILS_ENV. By default used "development" env'
|
27
|
+
task :start_background_env do
|
28
|
+
`cd #{Rails.root} | RAILS_ENV=#{ENV['RAILS_ENV'] || 'development'} bin/delayed_job start`
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Stop background env'
|
32
|
+
task :stop_background_env do
|
33
|
+
`cd #{Rails.root} | RAILS_ENV=#{ENV['RAILS_ENV'] || 'development'} bin/delayed_job stop`
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
desc 'Run init base by info'
|
38
|
+
task :init_base => :environment do
|
39
|
+
run_env
|
40
|
+
Nppes.background_init
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Run auto update'
|
44
|
+
task :auto_update => :environment do
|
45
|
+
run_env
|
46
|
+
Nppes.background_update(true)
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'Run update once'
|
50
|
+
task :update => :environment do
|
51
|
+
run_env
|
52
|
+
Nppes.background_update
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Nppes
|
4
|
+
module UpdatePack
|
5
|
+
class Base
|
6
|
+
class_attribute :file
|
7
|
+
|
8
|
+
def parse(file)
|
9
|
+
raise Exception.new('Block required') unless block_given?
|
10
|
+
file.each_with_index { |row, i| yield row unless i == 0 }
|
11
|
+
end
|
12
|
+
|
13
|
+
def split_row(row)
|
14
|
+
row.gsub(/\A"|"\n?\z/, '').split(/\",\"/)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Nppes
|
2
|
+
module UpdatePack
|
3
|
+
class Data < UpdatePack::Base
|
4
|
+
def initialize(data_file)
|
5
|
+
@file = data_file
|
6
|
+
end
|
7
|
+
|
8
|
+
def proceed
|
9
|
+
parse(@file) do |row|
|
10
|
+
proceed_row(row)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def proceed_row(row, required_fields = RequiredFields)
|
15
|
+
@fields = split_row(row)
|
16
|
+
|
17
|
+
npi = Nppes::NpIdentifier.where(npi: @fields[0]).first_or_initialize
|
18
|
+
|
19
|
+
required_fields.fields.each_pair { |k, v| npi.send("#{k}=", @fields[v]) }
|
20
|
+
|
21
|
+
# for submodels
|
22
|
+
#required_fields.relations.each_pair do |k, v|
|
23
|
+
# v.each do |entity|
|
24
|
+
# relation = npi.send(k).new
|
25
|
+
# entity.each_pair {|name, num| relation.send("#{name}=", @fields[num])}
|
26
|
+
# end
|
27
|
+
#end
|
28
|
+
|
29
|
+
#for submodel
|
30
|
+
#required_fields.relations.each_pair do |k, v|
|
31
|
+
# relation = npi.send(k).new
|
32
|
+
# entity.each_pair {|name, num| relation.send("#{name}=", @fields[num])}
|
33
|
+
#end
|
34
|
+
|
35
|
+
npi.save!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Nppes
|
2
|
+
module UpdatePack
|
3
|
+
class Header < UpdatePack::Base
|
4
|
+
class_attribute :fields
|
5
|
+
|
6
|
+
#ALIAS = {
|
7
|
+
#'NPI' => 'npi',
|
8
|
+
#'Entity Type Code' => 'entity_type_code',
|
9
|
+
#'Replacement NPI' => 'replacment_npi',
|
10
|
+
#'Employer Identification Number (EIN)' => ''
|
11
|
+
#
|
12
|
+
#"Provider Organization Name (Legal Business Name)"
|
13
|
+
#"Provider Last Name (Legal Name)"
|
14
|
+
#"Provider First Name"
|
15
|
+
#"Provider Middle Name"
|
16
|
+
#"Provider Name Prefix Text"
|
17
|
+
#"Provider Name Suffix Text"
|
18
|
+
#"Provider Credential Text"
|
19
|
+
#
|
20
|
+
#"Provider Other Organization Name"
|
21
|
+
#"Provider Other Organization Name Type Code"
|
22
|
+
#"Provider Other Last Name"
|
23
|
+
#"Provider Other First Name"
|
24
|
+
#"Provider Other Middle Name"
|
25
|
+
#"Provider Other Name Prefix Text"
|
26
|
+
#"Provider Other Name Suffix Text"
|
27
|
+
#"Provider Other Credential Text"
|
28
|
+
#"Provider Other Last Name Type Code"
|
29
|
+
#
|
30
|
+
#"Provider First Line Business Mailing Address"
|
31
|
+
#"Provider Second Line Business Mailing Address"
|
32
|
+
#"Provider Business Mailing Address City Name"
|
33
|
+
#"Provider Business Mailing Address State Name"
|
34
|
+
#"Provider Business Mailing Address Postal Code"
|
35
|
+
#"Provider Business Mailing Address Country Code (If outside U.S.)"
|
36
|
+
#"Provider Business Mailing Address Telephone Number"
|
37
|
+
#"Provider Business Mailing Address Fax Number"
|
38
|
+
#"Provider First Line Business Practice Location Address"
|
39
|
+
#"Provider Second Line Business Practice Location Address"
|
40
|
+
#"Provider Business Practice Location Address City Name"
|
41
|
+
#"Provider Business Practice Location Address State Name"
|
42
|
+
#"Provider Business Practice Location Address Postal Code"
|
43
|
+
#"Provider Business Practice Location Address Country Code (If outside U.S.)"
|
44
|
+
#"Provider Business Practice Location Address Telephone Number"
|
45
|
+
#"Provider Business Practice Location Address Fax Number"
|
46
|
+
#"Provider Enumeration Date" "Last Update Date"
|
47
|
+
#
|
48
|
+
#"NPI Deactivation Reason Code"
|
49
|
+
#"NPI Deactivation Date"
|
50
|
+
#"NPI Reactivation Date"
|
51
|
+
#"Provider Gender Code"
|
52
|
+
#
|
53
|
+
#"Authorized Official Last Name"
|
54
|
+
#"Authorized Official First Name"
|
55
|
+
#"Authorized Official Middle Name"
|
56
|
+
#"Authorized Official Title or Position"
|
57
|
+
#"Authorized Official Telephone Number"
|
58
|
+
#"Healthcare Provider Taxonomy Code_1"
|
59
|
+
#
|
60
|
+
#"Provider License Number_1"
|
61
|
+
#"Provider License Number State Code_1"
|
62
|
+
#"Healthcare Provider Primary Taxonomy Switch_1"
|
63
|
+
#
|
64
|
+
#"..."
|
65
|
+
#
|
66
|
+
#"Healthcare Provider Taxonomy Code_15"
|
67
|
+
#"Provider License Number_15"
|
68
|
+
#"Provider License Number State Code_15"
|
69
|
+
#"Healthcare Provider Primary Taxonomy Switch_15"
|
70
|
+
#
|
71
|
+
#
|
72
|
+
#
|
73
|
+
#"Other Provider Identifier_1"
|
74
|
+
#"Other Provider Identifier Type Code_1"
|
75
|
+
#"Other Provider Identifier State_1"
|
76
|
+
#"Other Provider Identifier Issuer_1"
|
77
|
+
#
|
78
|
+
#"Other Provider Identifier_2"
|
79
|
+
#"Other Provider Identifier Type Code_2"
|
80
|
+
#"Other Provider Identifier State_2"
|
81
|
+
#"Other Provider Identifier Issuer_2"
|
82
|
+
#
|
83
|
+
#"..."
|
84
|
+
#
|
85
|
+
#"Other Provider Identifier_15"
|
86
|
+
#"Other Provider Identifier Type Code_15"
|
87
|
+
#"Other Provider Identifier State_15"
|
88
|
+
#"Other Provider Identifier Issuer_15"
|
89
|
+
#
|
90
|
+
#
|
91
|
+
#"Is Sole Proprietor"
|
92
|
+
#"Is Organization Subpart"
|
93
|
+
#"Parent Organization LBN"
|
94
|
+
#"Parent Organization TIN"
|
95
|
+
#"Authorized Official Name Prefix Text"
|
96
|
+
#"Authorized Official Name Suffix Text"
|
97
|
+
#"Authorized Official Credential Text"
|
98
|
+
#
|
99
|
+
#"Healthcare Provider Taxonomy Group_1"
|
100
|
+
#"Healthcare Provider Taxonomy Group_2"
|
101
|
+
#}
|
102
|
+
|
103
|
+
def initialize(header_file)
|
104
|
+
@file = header_file
|
105
|
+
end
|
106
|
+
|
107
|
+
def proceed
|
108
|
+
parse(@file) do |row|
|
109
|
+
@fields = split_row(row)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'zip'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module Nppes
|
6
|
+
module UpdatePack
|
7
|
+
class Pack
|
8
|
+
class << self
|
9
|
+
def proceed(zip_file)
|
10
|
+
Nppes.logger.warn 'proceed file'
|
11
|
+
zip = Zip::File.open(zip_file)
|
12
|
+
|
13
|
+
data = zip.entries.detect {|entry| entry.name =~ /npidata_\d+-\d+\.csv/}
|
14
|
+
#head = zip.entries.detect {|entry| entry.name =~ /npidata_\d+-\d+FileHeader\.csv/}
|
15
|
+
|
16
|
+
raise Exception.new('head or data not found') unless data || head
|
17
|
+
|
18
|
+
#header = UpdatePack::Header.new(head.get_input_stream)
|
19
|
+
|
20
|
+
data = UpdatePack::Data.new(data.get_input_stream)
|
21
|
+
Nppes.logger.warn 'proceed data'
|
22
|
+
data.proceed
|
23
|
+
end
|
24
|
+
|
25
|
+
def proceed_updates
|
26
|
+
Nppes::NpUpdateCheck.proc_needed.each do |update|
|
27
|
+
proceed_update(update)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def background_proceed_updates
|
32
|
+
Nppes::NpUpdateCheck.proc_needed.each do |update|
|
33
|
+
Delayed::Job.enqueue(Nppes::Jobs::UpdaterJob.new(update))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def background_init_base
|
38
|
+
Delayed::Job.enqueue(Nppes::Jobs::IniterJob.new)
|
39
|
+
end
|
40
|
+
|
41
|
+
def init_base
|
42
|
+
Nppes.logger.warn 'find init file'
|
43
|
+
doc = Nokogiri::HTML(open(Nppes.updates_url))
|
44
|
+
link = doc.css('a').detect do |link|
|
45
|
+
link['href'] =~ Nppes.initiate_signature
|
46
|
+
end
|
47
|
+
raise Exception.new('Initial file not found') unless link
|
48
|
+
proceed(prepare_file(link['href']))
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_updates
|
52
|
+
Nppes.logger.warn 'find updates'
|
53
|
+
doc = Nokogiri::HTML(open(Nppes.updates_url))
|
54
|
+
signature = Nppes.weekly ? Nppes.weekly_signature : Nppes.monthly_signature
|
55
|
+
|
56
|
+
doc.css('a').each do |link|
|
57
|
+
Nppes::NpUpdateCheck.where(file_link: link['href']).first_or_create if link['href'] =~ signature
|
58
|
+
end
|
59
|
+
|
60
|
+
proceed_updates
|
61
|
+
end
|
62
|
+
|
63
|
+
def background_check_updates(continious = false)
|
64
|
+
Delayed::Job.enqueue(Nppes::Jobs::SearcherJob.new((Nppes.get_time_period if continious)))
|
65
|
+
end
|
66
|
+
|
67
|
+
def proceed_update(update)
|
68
|
+
begin
|
69
|
+
proceed(prepare_file(update.file_link))
|
70
|
+
rescue
|
71
|
+
update.update_attribute(:done, false)
|
72
|
+
else
|
73
|
+
update.update_attribute(:done, true)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
def prepare_file(file_link)
|
79
|
+
Nppes.logger.warn 'prepare file'
|
80
|
+
ret_file = open(file_link)
|
81
|
+
file = Tempfile.new(File.basename(file_link))
|
82
|
+
file << ret_file.read.force_encoding('utf-8')
|
83
|
+
file.flush
|
84
|
+
file.path
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Nppes
|
2
|
+
module UpdatePack
|
3
|
+
class RequiredFields
|
4
|
+
class_attribute :fields
|
5
|
+
class_attribute :relations
|
6
|
+
class_attribute :code_values
|
7
|
+
|
8
|
+
# not used at this time
|
9
|
+
self.code_values = {
|
10
|
+
entity_type_code: {
|
11
|
+
1 => 'individual',
|
12
|
+
2 => 'organization',
|
13
|
+
nil => nil
|
14
|
+
},
|
15
|
+
gender_code: {
|
16
|
+
'M' => 'male',
|
17
|
+
'F' => 'female',
|
18
|
+
nil => nil
|
19
|
+
},
|
20
|
+
npi_deactivation_reason_code: {
|
21
|
+
'DT' => 'death',
|
22
|
+
'DB' => 'disbandment',
|
23
|
+
'FR' => 'fraud',
|
24
|
+
'OT' => 'other',
|
25
|
+
nil => nil
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
self.fields = {
|
30
|
+
npi: 0,
|
31
|
+
npi_deactivation_reason_code: 38,
|
32
|
+
npi_deactivation_date: 39,
|
33
|
+
npi_reactivation_date: 40,
|
34
|
+
entity_type_code: 1,
|
35
|
+
|
36
|
+
last_name: 5,
|
37
|
+
first_name: 6,
|
38
|
+
middle_name: 7,
|
39
|
+
prefix: 8,
|
40
|
+
suffix: 9,
|
41
|
+
last_update_date: 37,
|
42
|
+
gender_code: 41,
|
43
|
+
|
44
|
+
#first_business_practice_address: 28,
|
45
|
+
#second_business_practice_address: 29,
|
46
|
+
#
|
47
|
+
#business_practice_city: 30,
|
48
|
+
#business_practice_state: 31,
|
49
|
+
#business_practice_postal_code: 32,
|
50
|
+
#business_practice_phone: 34,
|
51
|
+
#
|
52
|
+
#
|
53
|
+
#first_business_mailing_address: 20,
|
54
|
+
#second_business_mailing_address: 21,
|
55
|
+
#
|
56
|
+
#business_mailing_city: 22,
|
57
|
+
#business_mailing_state: 23,
|
58
|
+
#business_mailing_postal_code: 24,
|
59
|
+
#business_mailing_phone: 26,
|
60
|
+
#
|
61
|
+
#official_last_name: 42,
|
62
|
+
#official_first_name: 43,
|
63
|
+
#official_middle_name: 44,
|
64
|
+
#official_phone: 46
|
65
|
+
}
|
66
|
+
|
67
|
+
self.relations = {
|
68
|
+
np_licenses:
|
69
|
+
(0..14).each_with_object({}) do |i, ret|
|
70
|
+
ret.update(
|
71
|
+
taxonomy_code: 47 + (i * 4),
|
72
|
+
license_number: 48 + (i * 4),
|
73
|
+
license_number_state_code: 49 + (i * 4),
|
74
|
+
healhcare_taxonomy_switch: 50 + (i * 4)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
#class << self
|
80
|
+
# def proceed(header)
|
81
|
+
#
|
82
|
+
# end
|
83
|
+
#end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/nppes.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/nppes/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Jenua Boiko']
|
6
|
+
gem.email = ['jeyboy1985@gmail.com']
|
7
|
+
gem.description = %Q{}
|
8
|
+
gem.summary = %Q{}
|
9
|
+
gem.homepage = ''
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "nppes"
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.version = Nppes::VERSION
|
17
|
+
gem.rubygems_version = %q{1.8.6}
|
18
|
+
gem.license = 'MIT'
|
19
|
+
|
20
|
+
|
21
|
+
gem.add_dependency('rails', '>= 3.0.0')
|
22
|
+
gem.add_dependency('rubyzip')
|
23
|
+
gem.add_dependency('nokogiri')
|
24
|
+
gem.add_dependency('delayed_job_active_record')
|
25
|
+
gem.add_dependency('daemons')
|
26
|
+
|
27
|
+
gem.add_development_dependency('rspec-rails')
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Delayed Jobs' do
|
4
|
+
#it 'run env' do
|
5
|
+
# Rake::Task['nppes:start_background_env'].invoke unless already_run?
|
6
|
+
# Nppes.background_update(true)
|
7
|
+
#end
|
8
|
+
#
|
9
|
+
#describe 'recreation' do
|
10
|
+
# it 'on success' do
|
11
|
+
#
|
12
|
+
# end
|
13
|
+
#end
|
14
|
+
end
|
data/spec/parse_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'delayed_job'
|
5
|
+
|
6
|
+
#require 'lib/nppes/tasks/nppes.rake'
|
7
|
+
|
8
|
+
|
9
|
+
#require 'active_support/all'
|
10
|
+
#require 'action_mailer'
|
11
|
+
#require 'action_mailer_x509'
|
12
|
+
#require 'action_mailer_x509/x509'
|
13
|
+
#require 'action_mailer_x509/security_object'
|
14
|
+
#require 'action_mailer_x509/configuration'
|
15
|
+
#require 'models/notifier'
|
16
|
+
#require 'default_data'
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.after(:each) do
|
20
|
+
Delayed::Worker.reset
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nppes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jenua Boiko
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rubyzip
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: delayed_job_active_record
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: daemons
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec-rails
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: ''
|
111
|
+
email:
|
112
|
+
- jeyboy1985@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- Gemfile
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- Rakefile
|
122
|
+
- lib/generators/active_record/base_npi_data.rb
|
123
|
+
- lib/generators/active_record/license.rb
|
124
|
+
- lib/generators/active_record/update_check.rb
|
125
|
+
- lib/generators/nppes/install_generator.rb
|
126
|
+
- lib/generators/templates/delayed_jobs.rb
|
127
|
+
- lib/generators/templates/nppes.rb
|
128
|
+
- lib/nppes.rb
|
129
|
+
- lib/nppes/jobs.rb
|
130
|
+
- lib/nppes/jobs/initer_job.rb
|
131
|
+
- lib/nppes/jobs/searcher_job.rb
|
132
|
+
- lib/nppes/jobs/updater_job.rb
|
133
|
+
- lib/nppes/models.rb
|
134
|
+
- lib/nppes/np_identifier.rb
|
135
|
+
- lib/nppes/np_license.rb
|
136
|
+
- lib/nppes/np_update_check.rb
|
137
|
+
- lib/nppes/railtie.rb
|
138
|
+
- lib/nppes/tasks/nppes.rake
|
139
|
+
- lib/nppes/update_pack.rb
|
140
|
+
- lib/nppes/update_pack/base.rb
|
141
|
+
- lib/nppes/update_pack/data.rb
|
142
|
+
- lib/nppes/update_pack/header.rb
|
143
|
+
- lib/nppes/update_pack/pack.rb
|
144
|
+
- lib/nppes/update_pack/required_fields.rb
|
145
|
+
- lib/nppes/version.rb
|
146
|
+
- nppes.gemspec
|
147
|
+
- spec/delayed_jobs_spec.rb
|
148
|
+
- spec/parse_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage: ''
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
segments:
|
164
|
+
- 0
|
165
|
+
hash: 484778415
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ! '>='
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
segments:
|
173
|
+
- 0
|
174
|
+
hash: 484778415
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 1.8.24
|
178
|
+
signing_key:
|
179
|
+
specification_version: 3
|
180
|
+
summary: ''
|
181
|
+
test_files:
|
182
|
+
- spec/delayed_jobs_spec.rb
|
183
|
+
- spec/parse_spec.rb
|
184
|
+
- spec/spec_helper.rb
|