Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formulary drug stu2 #21

Open
wants to merge 6 commits into
base: formularydrugs
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,18 @@ def get_patient
def coverage_plans
# Read all of the insurance drug plans from the server
cp_type = "http://terminology.hl7.org/CodeSystem/v3-ActCode|DRUGPOL"

reply = @client.search(FHIR::InsurancePlan, search: { parameters: { type: cp_type}}).resource
@plansbyid = build_coverage_plans(reply)
@plansbyid = JSON.parse(build_coverage_plans(reply).to_json).deep_symbolize_keys
@formulary_items_and_drugs = formulary_items_and_drugs
@formulary_items = @formulary_items_and_drugs[:formulary_items]
@formulary_drugs = @formulary_items_and_drugs[:formulary_drugs]
@locationsbyid = locations
@cp_options = build_coverage_plan_options(reply)
session[:plansbyid] = compress_hash(@plansbyid.to_json)
session[:locationsbyid] = compress_hash(@locationsbyid.to_json)
session[:cp_options] = compress_hash(@cp_options)
session[:formularyitemsbyid] = compress_hash(@formulary_items.to_json)
session[:formularydrugsbyid] = compress_hash(@formulary_drugs.to_json)

# Prepare the query string for display on the page
@search = URI.decode(reply.link.select { |l| l.relation === "self"}.first.url) if reply.link.first
Expand Down Expand Up @@ -65,6 +69,37 @@ def get_plansbyid

#-----------------------------------------------------------------------------

def get_formularyItemsById
if session[:formularyitemsbyid]
@formularyitemsbyid = JSON.parse(decompress_hash(session[:formularyitemsbyid]))
@cp_options = decompress_hash(session[:cp_options])
@search = session[:query]
else
puts "get_formularyItemsById: session[:formularyitemsbyid] is nil, calling formulary_items "
@formularyitemsbyid = nil
@cp_options = [["N/A (Must connect first)", "-"]]
formulary_items_and_drugs
end
end

#-----------------------------------------------------------------------------


def get_formularyDrugsById
if session[:formularydrugsbyid]
@formularydrugsbyid = JSON.parse(decompress_hash(session[:formularydrugsbyid]))
@cp_options = decompress_hash(session[:cp_options])
@search = session[:query]
else
puts "get_formularyDrugsById: session[:formularydrugsbyid] is nil, calling formulary_drugs "
@formularydrugsbyid = nil
@cp_options = [["N/A (Must connect first)", "-"]]
formulary_items_and_drugs
end
end

#-----------------------------------------------------------------------------

def locations
profile = "http://hl7.org/fhir/us/davinci-drug-formulary/StructureDefinition/usdf-InsurancePlanLocation"
bundle = @client.search(FHIR::Location, search: { parameters: { _profile: profile}}).resource&.entry || []
Expand All @@ -76,7 +111,34 @@ def locations
end

#-----------------------------------------------------------------------------

def formulary_items_and_drugs
profile = "http://hl7.org/fhir/us/davinci-drug-formulary/StructureDefinition/usdf-FormularyItem"
bundle = @client.search(FHIR::Basic, search: { parameters: {_profile: profile, _include: "Basic:subject", _count: 500 }}).resource&.entry || []
formulary_drugs = {}
formulary_items = bundle.each_with_object({}) do | entry, formularyItemById |
if entry.search.mode == "match"
formularyItemById[entry.resource.id] = FormularyItem.new(entry.resource, @plansbyid)
else
formulary_drugs[entry.resource.id] = MedicationKnowledge.new(entry.resource)
end
end
@formulary_items_and_drugs = {formulary_items: formulary_items.deep_symbolize_keys, formulary_drugs: formulary_drugs.deep_symbolize_keys}
end

#-----------------------------------------------------------------------------

def formulary_drugs
profile = "http://hl7.org/fhir/us/davinci-drug-formulary/StructureDefinition/usdf-FormularyDrug"
bundle = @client.search(FHIR::MedicationKnowledge, search: { parameters: {_profile: profile}}).resource&.entry || []
formulary_drugs = bundle.each_with_object({}) do | entry, formularyDrugById |
formularyDrugById[entry.resource.id] = MedicationKnowledge.new(entry.resource)
end
formulary_drugs.deep_symbolize_keys
end

#-----------------------------------------------------------------------------

def payer_plans
# Read all payer insurance plans from the server
payerplan_type = "http://hl7.org/fhir/us/davinci-pdex-plan-net/CodeSystem/InsuranceProductTypeCS|"
Expand Down
11 changes: 6 additions & 5 deletions app/controllers/compare_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class CompareController < ApplicationController
def index
@codes = nil
@params = nil

get_plansbyid
if params[:search].length>0 or params[:code].length>0
@drugname = params[:search].split(' ').first
Expand Down Expand Up @@ -109,12 +108,14 @@ def set_table
chosen = @cache[:fis]
@drugsbyid = build_formulary_drugs(@cache[:fds])
@table_rows = Hash.new

chosen.collect!{ |fi| FormularyItem.new(fi, @plansbyid, @drugsbyid) }
chosen.collect!{ |fi| FormularyItem.new(fi, @plansbyid)}
chosen.each do |fi|
code = fi.rxnorm_code
plan = fi.plan_id
fd = FormularyDrug.new(@cache[:fds].find { |drug| drug.id == fi.subject.reference.split('/')[1] })
code = fi.subject.reference.split('/')[1]
plan = fi.formulary.reference.split('/')[1]
@table_rows.has_key?(code) ? @table_rows[code][plan] = fi : @table_rows[code] = { plan => fi }
@table_rows[code][code] = fd

end
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/formularies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def index
@drugsbyid = build_formulary_drugs(fhir_formularydrugs)
@formularydrugs = []
fhir_formularyitems.each do |fhir_formularyitem|
@formularydrugs << FormularyItem.new(fhir_formularyitem,@plansbyid, @drugsbyid)
@formularydrugs << FormularyItem.new(fhir_formularyitem, @plansbyid)
end

# Prepare the query string for display on the page
Expand All @@ -68,7 +68,7 @@ def show
# fhir_formularydrug = @@bundle.entry.map(&:resource).first
get_plansbyid
@drugsbyid = build_formulary_drugs(fhir_formularydrugs)
@formulary_drug = FormularyItem.new(fhir_formularyitem, @plansbyid, @drugsbyid)
@formulary_drug = FormularyItem.new(fhir_formularyitem, @plansbyid)

# Prepare the query string for display on the page
@search = "<Search String in Returned Bundle is empty>"
Expand Down
42 changes: 42 additions & 0 deletions app/controllers/formularyitems_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
################################################################################
#
# FormularItems Controller => Formulary Item (Basic) profile
#
# Copyright (c) 2021 The MITRE Corporation. All rights reserved.
#
################################################################################

require 'json'

class FormularyitemsController < ApplicationController

before_action :check_formulary_server_connection, only: [ :index]

#-----------------------------------------------------------------------------

# GET /formularyitems

def index
get_plansbyid
get_payers_byid
get_formularyItemsById
get_formularyDrugsById
@formulary_items = @formularyitemsbyid.values.select do |formulary_item|
formulary_drug = @formularydrugsbyid.values.find {|drug| formulary_item["subject"]["reference"] == "MedicationKnowledge/" + drug["id"]}
include_in_results = true
if params[:coverage].present?
include_in_results = include_in_results && formulary_item["formulary"]["reference"] == "InsurancePlan/" + params[:coverage]
end
if params[:drug_tier].present?
include_in_results = include_in_results && formulary_item["drug_tier"]["code"] == params[:drug_tier]
end
if params[:name].present?
include_in_results = include_in_results && params[:name].in?(formulary_drug["code"]["display"])
end
include_in_results
end
end

#-----------------------------------------------------------------------------

end
133 changes: 30 additions & 103 deletions app/models/formulary_item.rb
Original file line number Diff line number Diff line change
@@ -1,125 +1,52 @@
################################################################################
#
# Formulary Item Model
# FormularyItem Model => FormularyItem profile
#
# Copyright (c) 2021 The MITRE Corporation. All rights reserved.
#
################################################################################

class FormularyItem < Resource
class FormularyItem

include ActiveModel::Model

attr_accessor :drug_tier, :drug_class, :id, :plan_id, :drug_name, :rxnorm_code,
:prior_auth, :step_therapy, :quantity_limit, :errors, :step_therapy_newstart,
:warnings, :plan_id_path, :plan_id_name, :rxnorm_path, :prior_auth_newstart,
:copay, :coinsurancerate, :formulary_id_path, :plan, :plansbyid, :mailorder

#-----------------------------------------------------------------------------

def initialize(fhir_formulary, plansbyid, drugsbyid)
@id = parse_id(fhir_formulary)
drug = drugsbyid[parse_reference_id(fhir_formulary.subject.reference).to_sym]
@drug_name = drug[:drug_name]
@rxnorm_code = drug[:rxnorm_code]
@plansbyid = plansbyid
#@drug_class = parse_drug_class(fhir_formulary)
@rxnorm_path = "https://mor.nlm.nih.gov/RxNav/search?searchBy=RXCUI&searchTerm=" + @rxnorm_code
@formulary_id_path = "/formularies/#{@id}"
parse_extensions(fhir_formulary)
@plan = plansbyid[@plan_id.to_sym]
# Test inclusion of drug tier info in formulary drug for display
@tier = @plan[:tiers][@drug_tier.to_sym]
if @tier
attr_accessor :id, :subject, :formulary, :drug_tier, :prior_authorization, :quantity_limit, :step_therapy_limit,
:status, :period, :pharmacy_type, :copay, :coinsurancerate

def initialize(fhir_formularyitem, plansbyid)
@id = fhir_formularyitem.id
@subject = fhir_formularyitem.subject

@extension = fhir_formularyitem.extension
@formulary = find_element_in_extension(@extension, "DrugPlanReference").valueReference
@drug_tier = find_element_in_extension(@extension, "DrugTierID").valueCodeableConcept.coding.first
@prior_authorization = find_element_in_extension(@extension, "PriorAuthorization").valueBoolean
@quantity_limit = find_element_in_extension(@extension, "QuantityLimit").valueBoolean
@step_therapy_limit = find_element_in_extension(@extension, "StepTherapyLimit").valueBoolean
@status = find_element_in_extension(@extension, "AvailabilityStatus").valueCode
@period = find_element_in_extension(@extension, "AvailabilityPeriod").valuePeriod
@pharmacy_type = find_element_in_extension(@extension, "PharmacyType").valueCodeableConcept.coding.first
@plan = plansbyid[@formulary.reference.split('/')[1].to_sym]
@tier = @plan[:tiers][@drug_tier.code.to_sym]
if @tier
@copay = @tier["1 month in network retail".to_sym][:copay]
@coinsurancerate = @tier["1 month in network retail".to_sym][:coinsurancerate]
else
@copay = "missing"
@coinsurancerate = "missing"
end

end

#-----------------------------------------------------------------------------
private
#-----------------------------------------------------------------------------

# Isolates the ID from the formulary drug resource.

def parse_id(fhir_formulary)
return fhir_formulary.id
end

#-----------------------------------------------------------------------------

def parse_reference_id(reference)
return reference.split("/").last
end

#-----------------------------------------------------------------------------

# Parses the values within the extensions defined by the formulary drug
# resource.

def parse_extensions(fhir_formulary)
extensions = fhir_formulary.extension
if extensions.present?
extensions.each do |extension|
if extension.url.include?("DrugTierID")
@drug_tier = parse_drug_tier(extension)
elsif extension.url.include?("PharmacyType")
if parse_drug_tier(extension).include?("mail")
@mailorder = true
end

elsif extension.url.include?("PriorAuthorization-extension")
@prior_auth = extension.valueBoolean
elsif extension.url.include?("PriorAuthorizationNewStartsOnly")
@prior_auth_newstart = extension.valueBoolean
elsif extension.url.include?("StepTherapyLimit-extension")
@step_therapy = extension.valueBoolean
elsif extension.url.include?("StepTherapyLimitNewStartsOnly")
@step_therapy_newstart = extension.valueBoolean
elsif extension.url.include?("QuantityLimit")
@quantity_limit = extension.valueBoolean
elsif extension.url.include?("DrugPlanReference")
@plan_id = parse_reference_id(extension.valueReference.reference)
@plan = plansbyid[plan_id.to_sym]
@plan_id_path = "/coverageplans/#{plan_id}"
@plan_id_name = plan[:name]
end
end
else
@drug_tier = "Required extensions not specified"
end
end

#-----------------------------------------------------------------------------

def parse_drug_tier(extension)
if (concept = extension.valueCodeableConcept).present?
if (coding = concept.coding).present?
value = code_list(coding)
else
value = "Drug tier not specified"
end
else
value = "Codeable concept not present"
end

return value
end

#-----------------------------------------------------------------------------
def display_list(list)
list.map{ |element| element.display }.join(', ')
end

#-----------------------------------------------------------------------------

# Concatenates a list of code elements.

def code_list(list)
list.map{ |element| element.code }.join(', ')
end
private

def find_element_in_extension(extensions, reference_key)
extensions.each do |extension|
if extension.url.include?(reference_key)
return extension
end
end
end
end
25 changes: 25 additions & 0 deletions app/models/medication_knowledge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
################################################################################
#
# FormularyMedicationKnowledge Model => MedicationKnowledge profile
#
# Copyright (c) 2021 The MITRE Corporation. All rights reserved.
#
################################################################################

class MedicationKnowledge

include ActiveModel::Model

attr_accessor :id, :status, :code, :synonym, :dose_form, :related_medication_knowledge, :medicine_classification

def initialize(fhir_medicationknowledge)
@id = fhir_medicationknowledge.id
@code = fhir_medicationknowledge.code.coding.first
@status = fhir_medicationknowledge.status
@synonym = fhir_medicationknowledge.synonym
@dose_form = fhir_medicationknowledge.doseForm
@related_medication_knowledge = fhir_medicationknowledge.relatedMedicationKnowledge
@medicine_classification = fhir_medicationknowledge.medicineClassification

end
end
Loading