Skip to content

Instantly share code, notes, and snippets.

@jgautsch
Created August 22, 2014 02:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgautsch/22a01facc880e76d9143 to your computer and use it in GitHub Desktop.
Save jgautsch/22a01facc880e76d9143 to your computer and use it in GitHub Desktop.
classes.rb, The Classes that the NPI MapReduce script depends on
# ###########################################################
# Data Processing
# ###########################################################
module DataProcessing
class TaxonomyCache
def initialize
@@specialties = Taxonomies::Specialty.all[0..-1].group_by(&:taxonomy)
@@specialties.each do |k, v|
@@specialties[k] = v.first
end
end
def find(*args)
args.flatten!
result = []
args.each do |tax|
if @@specialties.has_key?(tax)
result << @@specialties[tax]
end
end
result
end
end
module Stream
class Row
def initialize(row)
@values = CSV.parse(row).first
if @values.size != 329
puts "ROW SIZE: #{@values.size}"
raise "Wrong Size Row"
end
def active?
# 39 --> "NPI Deactivation Date",
# 40 --> "NPI Reactivation Date",
# if it has a Deactivation date and it doesn't have a reactivation date it's inactive
# if the opposite of the above, it's active
# DeMorgan's FTW
value_at_index(39).blank? || !value_at_index(40).blank?
end
def entity_type
type_code = value_at_index(1)
if type_code == '1'
'Individual'
elsif type_code == '2'
'Organization'
elsif type_code == 'Entity Type Code'
'HeaderRow'
else
raise "Invalid Data - Entity Type Code: #{type_code}"
end
end
def taxonomy_codes
taxonomy_indexes = [47,50,51,54,55,58,59,62,63,66,67,
70,71,74,75,78,79,82,83,86,87,90,
91,94,95,98,99,102,103,106,314,
315,316,317,318,319,320,321,322,
323,324,325,326,327,328]
taxonomy_indexes.map {|i| value_at_index(i) }.reject!(&:blank?)
end
def individual_provider_attributes
attrs = {
npi: value_at_index(0),
replacement_npi: value_at_index(2),
ein: value_at_index(3),
last_name: value_at_index(5),
first_name: value_at_index(6),
middle_name: value_at_index(7),
name_prefix: value_at_index(8),
name_suffix: value_at_index(9),
provider_credential: value_at_index(10),
other_last_name: value_at_index(13),
other_first_name: value_at_index(14),
other_middle_name: value_at_index(15),
other_name_prefix: value_at_index(16),
other_name_suffix: value_at_index(17),
other_provider_credential: value_at_index(18),
other_last_name_type_code: value_at_index(19)
}
end
def organization_provider_attributes
attrs = {
npi: value_at_index(0),
replacement_npi: value_at_index(2),
ein: value_at_index(3),
name: value_at_index(4),
other_name: value_at_index(11),
other_name_type_code: value_at_index(12)
}
end
def mailing_address_attributes
attrs = {
first_line: value_at_index(20),
second_line: value_at_index(21),
city: value_at_index(22),
state: value_at_index(23),
postal_code: value_at_index(24),
country_code: value_at_index(25),
telephone_number: value_at_index(26),
fax_number: value_at_index(27)
}
end
def practice_address_attributes
attrs = {
first_line: value_at_index(28),
second_line: value_at_index(29),
city: value_at_index(30),
state: value_at_index(31),
postal_code: value_at_index(32),
country_code: value_at_index(33),
telephone_number: value_at_index(34),
fax_number: value_at_index(35)
}
end
def value_at_index(index)
value = @values[index]
value.blank? ? nil : value
end
end
end
class RowObjectBuilder
attr_accessor :object
def initialize(row, tax_cache)
@tax_cache = tax_cache
@row = Row.new(row)
end
def objectify
if @row.active? and @row.entity_type != 'HeaderRow'
if @row.entity_type == 'Individual'
@object = create_individual_provider
elsif @row.entity_type == 'Organization'
@object = create_organization_provider
else
raise 'Invalid Data'
end
associate_taxonomies if @object
associate_addresses if @object
@object.save if @object
puts @object.name if @object
end
end
private
def create_individual_provider
Providers::Individual.create(@row.individual_provider_attributes)
end
def create_organization_provider
Providers::Organization.create(@row.organization_provider_attributes)
end
def associate_taxonomies
taxonomy_codes = @row.taxonomy_codes
specs = @tax_cache.find(taxonomy_codes)
@object.specialties = specs
end
def associate_addresses
address1 = Locations::MailingAddress.new(@row.mailing_address_attributes)
address2 = Locations::PracticeAddress.new(@row.practice_address_attributes)
@object.addresses = [
(address1.valid? ? address1 : nil),
(address2.valid? ? address2 : nil)
].compact
end
end
end
end
# ###########################################################
# Locations
# ###########################################################
module Locations
class BusinessAddress
include Mongoid::Document
include Geocoder::Model::Mongoid
after_validation :geocode
belongs_to :provider, class_name: 'Providers::Provider'
geocoded_by :address
validates_presence_of :first_line
validates_presence_of :city
validates_presence_of :state
validates_presence_of :postal_code
field :first_line, type: String
field :second_line, type: String
field :city, type: String
field :state, type: String
field :postal_code, type: String
field :country_code, type: String
field :telephone_number, type: String
field :fax_number, type: String
field :coordinates, type: Array
def address
if first_line && city && state && postal_code
if second_line.blank?
return "#{first_line}, #{city}, #{state}, #{postal_code.first(5)}"
else
return "#{first_line}, #{second_line}, #{city}, #{state}, #{postal_code.first(5)}"
end
end
end
end
class MailingAddress < BusinessAddress
end
class PracticeAddress < BusinessAddress
end
end
# ###########################################################
# Providers
# ###########################################################
module Providers
class Provider
include Mongoid::Document
field :npi, type: String
field :replacement_npi, type: String
field :ein, type: String
has_many :addresses, class_name: 'Locations::BusinessAddress', dependent: :destroy
has_and_belongs_to_many :specialties, class_name: 'Taxonomies::Specialty'
end
class Individual < Providers::Provider
field :last_name, type: String
field :first_name, type: String
field :middle_name, type: String
field :name_prefix, type: String
field :name_suffix, type: String
field :provider_credential, type: String
field :other_last_name, type: String
field :other_first_name, type: String
field :other_middle_name, type: String
field :other_name_prefix, type: String
field :other_name_suffix, type: String
field :other_provider_credential, type: String
field :other_last_name_type_code, type: String
def name
"#{name_prefix} #{first_name} #{last_name} #{name_suffix}, #{provider_credential}"
end
end
class Organization < Providers::Provider
field :name, type: String
field :other_name, type: String
field :other_name_type_code, type: String
# field :
end
end
# ###########################################################
# Taxonomies
# ###########################################################
module Taxonomies
class Catagory
include Mongoid::Document
has_many :types
field :name, type: String
end
class Type
include Mongoid::Document
belongs_to :catagory
has_many :classifications
field :name, type: String
field :description, type: String
end
class Specialty
include Mongoid::Document
has_and_belongs_to_many :providers, class_name: 'Providers::Provider'
field :name, type: String
field :taxonomy, type: String
field :active, type: Boolean
field :description, type: String
end
class Classification < Taxonomies::Specialty
belongs_to :type
has_many :specializations
end
class Specialization < Taxonomies::Specialty
belongs_to :classification
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment