nppes 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|