Its been a while
CI / scan_ruby (push) Failing after 2m13s
CI / lint (push) Failing after 20s

This commit is contained in:
Jason Jordan
2026-07-23 10:41:46 -04:00
parent 16fadfd529
commit 9853d58469
83 changed files with 1978 additions and 243 deletions
+4 -4
View File
@@ -42,15 +42,15 @@ module Api
end
end
# post /logout -> NOW with real token blacklisting
# adds the current token to blacklist so it can't be used again
# post /logout -> NOW with real token retireing
# adds the current token to retire so it can't be used again
# authorize_request ensures @current_user and token are present
def logout
header = request.headers["Authorization"]
token = header.split(" ").last if header
decoded = JsonWebToken.decode(token)
BlacklistedToken.create!(
RetiredToken.create!(
jti: decoded[:jti],
user_id: decoded[:user_id],
exp: Time.at(decoded[:exp])
@@ -59,7 +59,7 @@ module Api
# also revoke all refresh tokens for this user
@current_user.refresh_tokens.update_all(revoked: true)
render json: { message: "Successfully logged out. Token blacklisted." }, status: :ok
render json: { message: "Successfully logged out. Token retired." }, status: :ok
rescue StandardError => e
render json: { error: "Logout failed: #{e.message}" }, status: :unprocessable_entity
end
@@ -0,0 +1,16 @@
module Api
module V1
class BrokersController < ApplicationController
# before_action :authenticate_user!
def employers_list
broker_id = params[:id]
broker = Baclight::Broker.find(broker_id)
employers = broker.baclight_employers.order(:name).map { |emp| {name: emp.name, entity_key: emp.pl_plan_key }}
render json: employers, status: :ok
end
end
end
end
@@ -0,0 +1,8 @@
module Api
module V1
class CarriersController < ApplicationController
before_action :authenticate_user!
end
end
end
@@ -0,0 +1,18 @@
module Api
module V1
class ClaimsController < ApplicationController
def member_claims
pb_entity_key = params[:id]
member_claims = MemberClaimsService.new(pb_entity_key).call
if member_claims.present?
render json: member_claims, status: :ok
else
render json: { error: "Member Claims not found" }, status: :not_found
end
end
end
end
end
@@ -0,0 +1,36 @@
module Api
module V1
class EmployersController < ApplicationController
# before_action :authenticate_user!
def id_cards
pl_plan_key = params[:id]
id_cards = EmployersService::IdCards.new(pl_plan_key).call
if id_cards.code == 200
content_disposition = id_cards.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
# filename = params[:filename].presence || 'employer_idcards.zip'
send_data(
id_cards.body,
type: 'application/zip',
filename: filename,
disposition: 'attachment'
)
else
render json: { error: "Employer not found" }, status: :not_found
end
end
def members_list
pl_plan_key = params[:id]
employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
members = employer.baclight_members.active.order(:name).map { |mem| {name: mem.name, entity_key: mem.pb_entity_key}}
render json: members, status: :ok
end
end
end
end
@@ -0,0 +1,96 @@
module Api
module V1
class IdCardsController < ApplicationController
def member_card
pb_entity_key = params[:id]
layout = params[:layout]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
# authorize :id_cards, @member
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/member_card/#{pb_entity_key}/#{layout}"
}
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/pdf' },
stream_body: true
)
if response.code == 200
content_disposition = response.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
disposition = layout == "MobileDisplayCard" ? 'inline' : 'attachment'
send_data(
response.body,
type: 'application/pdf',
filename: filename,
disposition: disposition
)
else
render json: { error: "Member not found" }, status: :not_found
end
end
def member_benefits
pb_entity_key = params[:id]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
plan_id = @member.id_card_plan_id
plan_benefits = Baclight::IdCardPlan.joins(:baclight_id_card_plan_benefits)
.select('id_card_plans.id, id_card_plans.title, id_card_plan_benefits.id, id_card_plan_benefits.sequence, id_card_plan_benefits.benefit, id_card_plan_benefits.benefit_desc')
.where(id: plan_id)
.distinct
if plan_benefits.present?
render json: plan_benefits, status: :ok
else
render json: { error: "Plan Benefits not found" }, status: :not_found
end
end
def employer_cards
pl_plan_key = params[:id]
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
# authorize :id_cards, @employer
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/employer_cards/#{pl_plan_key}"
}
# Send POST with params and enable streaming
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/zip' },
stream_body: true
)
if response.code == 200
content_disposition = response.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
# filename = params[:filename].presence || 'employer_idcards.zip'
send_data(
response.body,
type: 'application/zip',
filename: filename,
disposition: 'attachment'
)
else
render json: { error: "Employer not found" }, status: :not_found
end
end
end
end
end
@@ -0,0 +1,74 @@
module Api
module V1
class MembersController < ApplicationController
# before_action :authenticate_user!
def initialize_dashboard
pb_entity_key = params[:id]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
authorize @member
dashboard_data = MembersService::InitializeDashboard.new(@member).call
render json: dashboard_data, status: :ok
end
def id_card
pb_entity_key = params[:id]
layout = params[:layout]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
# authorize @member
generated_id_card = MembersService::IdCard.new(@member, layout).call
if generated_id_card.code == 200
content_disposition = generated_id_card.headers['Content-Disposition']
filename = content_disposition[/filename="?([^"]*)"?/, 1]
# filename = params[:filename].presence || 'employer_idcards.zip'
send_data(
generated_id_card.body,
type: 'application/pdf',
filename: filename,
disposition: 'inline'
)
else
render json: { error: "Member not found" }, status: :not_found
end
end
def network_provider
pl_plan_key = params[:id]
network_provider = Baclight::IdCardSetup.find_by(pl_plan_key: pl_plan_key).slice(:network_provider)
if network_provider.present?
render json: network_provider, status: :ok
else
render json: { error: "Network Provider not found" }, status: :not_found
end
end
def plan_benefits
pb_entity_key = params[:id]
plan_benefits = MembersService::PlanBenefits.new(pb_entity_key).call
if plan_benefits.present?
render json: plan_benefits, status: :ok
else
render json: { error: "Plan Benefits not found" }, status: :not_found
end
end
def claims
pb_entity_key = params[:id]
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
recent_claims = MembersService::Claims.new(@member).call
render json: recent_claims, status: :ok
end
end
end
end
@@ -0,0 +1,19 @@
module Api
module V1
class NetworkProviderController < ApplicationController
def employer_network_provider
pl_plan_key = params[:id]
network_provider = Baclight::IdCardSetup.find_by(pl_plan_key: pl_plan_key).slice(:network_provider)
if network_provider.present?
render json: network_provider, status: :ok
else
render json: { error: "Network Provider not found" }, status: :not_found
end
end
end
end
end
@@ -0,0 +1,8 @@
module Api
module V1
class ProvidersController < ApplicationController
before_action :authenticate_user!
end
end
end
@@ -1,2 +1,3 @@
class ApplicationController < ActionController::API
include Pundit::Authorization
end
@@ -19,8 +19,8 @@ module AuthorizeRequest
begin
decoded = JsonWebToken.decode(token)
# check if token is blacklisted (logged out)
if BlacklistedToken.blacklisted?(decoded[:jti])
# check if token is retired (logged out)
if RetiredToken.retired?(decoded[:jti])
render json: { error: "Token has been revoked" }, status: :unauthorized
return
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
class Users::ConfirmationsController < Devise::ConfirmationsController
# GET /resource/confirmation/new
# def new
# super
# end
# POST /resource/confirmation
# def create
# super
# end
# GET /resource/confirmation?confirmation_token=abcdef
# def show
# super
# end
# protected
# The path used after resending confirmation instructions.
# def after_resending_confirmation_instructions_path_for(resource_name)
# super(resource_name)
# end
# The path used after confirmation.
# def after_confirmation_path_for(resource_name, resource)
# super(resource_name, resource)
# end
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# You should configure your model like this:
# devise :omniauthable, omniauth_providers: [:twitter]
# You should also create an action method in this controller like this:
# def twitter
# end
# More info at:
# https://github.com/heartcombo/devise#omniauth
# GET|POST /resource/auth/twitter
# def passthru
# super
# end
# GET|POST /users/auth/twitter/callback
# def failure
# super
# end
# protected
# The path used when OmniAuth fails
# def after_omniauth_failure_path_for(scope)
# super(scope)
# end
end
@@ -0,0 +1,34 @@
# frozen_string_literal: true
class Users::PasswordsController < Devise::PasswordsController
# GET /resource/password/new
# def new
# super
# end
# POST /resource/password
# def create
# super
# end
# GET /resource/password/edit?reset_password_token=abcdef
# def edit
# super
# end
# PUT /resource/password
# def update
# super
# end
# protected
# def after_resetting_password_path_for(resource)
# super(resource)
# end
# The path used after sending reset password instructions
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
end
@@ -0,0 +1,105 @@
# frozen_string_literal: true
class Users::RegistrationsController < Devise::RegistrationsController
respond_to :json
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
# GET /resource/sign_up
# def new
# super
# end
# POST /resource
# def create
# super do |resource|
# resource.sync_role_entity!
# end
# end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
# protected
private
# def respond_with(resource, _opts = {})
# if resource.persisted?
# render json: {
# status: { code: 200, message: 'Signed up successfully.' },
# data: resource
# }, status: :ok
# else
# render json: {
# status: { message: "User couldn't be created successfully. #{resource.errors.full_messages.to_sentence}" }
# }, status: :unprocessable_entity
# end
# end
def respond_with(resource, _opts = {})
if resource.persisted?
# Customize what is returned upon successful login here
render json: {
message: "Signed up successfully.",
user: {
id: resource.id,
email: resource.email,
name: resource.name,
role: resource.role,
role_id: resource.role_id,
jti: resource.jti,
keychain: resource.keychain,
created_at: resource.created_at,
updated_at: resource.updated_at
}
}, status: :ok
else
render json: {
status: { message: "User couldn't be created successfully. #{resource.errors.full_messages.to_sentence}" }
}, status: :unprocessable_entity
end
end
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:role, :role_id, :date_of_birth, :last_four_ssn])
end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
end
@@ -0,0 +1,49 @@
# frozen_string_literal: true
class Users::SessionsController < Devise::SessionsController
respond_to :json
# POST /resource/sign_in
# def create
# super
# end
# DELETE /resource/sign_out
# def destroy
# super
# end
private
def respond_with(resource, _opts = {})
puts
render json: {
status: { code: 200, message: 'Logged in successfully.' },
user: {
id: resource.id,
email: resource.email,
name: resource.name,
role: resource.role,
role_id: resource.role_id,
jti: resource.jti,
keychain: resource.keychain,
created_at: resource.created_at,
updated_at: resource.updated_at
}
}, status: :ok
end
def respond_to_on_destroy
if current_user
render json: {
status: 200,
message: "Logged out successfully."
}, status: :ok
else
render json: {
status: 401,
message: "Couldn't find an active session."
}, status: :unauthorized
end
end
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
class Users::UnlocksController < Devise::UnlocksController
# GET /resource/unlock/new
# def new
# super
# end
# POST /resource/unlock
# def create
# super
# end
# GET /resource/unlock?unlock_token=abcdef
# def show
# super
# end
# protected
# The path used after sending unlock password instructions
# def after_sending_unlock_instructions_path_for(resource)
# super(resource)
# end
# The path used after unlocking the resource
# def after_unlock_path_for(resource)
# super(resource)
# end
end
+2
View File
@@ -1,3 +1,5 @@
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
establish_connection :primary
end
+19
View File
@@ -0,0 +1,19 @@
module Baclight
class Broker < BaclightRecord
self.table_name = 'Brokers'
belongs_to :baclight_carrier, class_name: "Baclight::Carrier", foreign_key: "carrier_id"
has_many :baclight_employers, class_name: "Baclight::Employer", foreign_key: "broker_id", primary_key: "id"
has_many :baclight_members,
through: :baclight_employers,
source: :baclight_member
alias_attribute :id, :id
alias_attribute :name, :name
alias_attribute :carrier_id, :carrier_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+20
View File
@@ -0,0 +1,20 @@
module Baclight
class Carrier < BaclightRecord
self.table_name = 'Carriers'
has_many :baclight_brokers, class_name: "Baclight::Broker", foreign_key: "carrier_id", primary_key: "id"
has_many :baclight_employers,
through: :baclight_brokers,
source: :baclight_employer
has_many :baclight_members,
through: :baclight_employers,
source: :baclight_member
alias_attribute :id, :id
alias_attribute :name, :name
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+31
View File
@@ -0,0 +1,31 @@
module Baclight
class Employer < BaclightRecord
self.table_name = 'Employers'
belongs_to :baclight_broker, class_name: "Baclight::Broker", foreign_key: "broker_id"
has_many :baclight_members, class_name: "Baclight::Member", foreign_key: "employer_id", primary_key: "id"
alias_attribute :id, :id
alias_attribute :name, :name
alias_attribute :slug, :slug
alias_attribute :pl_plan_key, :pl_plan_key
alias_attribute :company_pb_entity_key, :company_pb_entity_key
alias_attribute :plan_id, :plan_id
alias_attribute :group_number, :group_number
alias_attribute :effective_date, :effective_date
alias_attribute :active, :active
alias_attribute :initialized, :initialized
alias_attribute :broker_id, :broker_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
def belongs_to_levels
self.joins(baclight_broker: :baclight_carrier).select(
'baclight_broker.id AS broker_id',
'baclight_carrier.id AS carrier_id'
)
end
end
end
+18
View File
@@ -0,0 +1,18 @@
module Baclight
class IdCardPlan < BaclightRecord
self.table_name = 'id_card_plans'
has_many :baclight_id_card_plan_benefits, class_name: "Baclight::IdCardPlanBenefit", foreign_key: "plan_id", primary_key: "id"
alias_attribute :id, :id
alias_attribute :title, :title
alias_attribute :pb_product_key, :pb_product_key
alias_attribute :pl_plan_key, :pl_plan_key
alias_attribute :template, :template
alias_attribute :setup_id, :setup_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
@@ -0,0 +1,17 @@
module Baclight
class IdCardPlanBenefit < BaclightRecord
self.table_name = 'id_card_plan_benefits'
belongs_to :baclight_id_card_plan, class_name: "Baclight::IdCardPlan", foreign_key: "plan_id"
alias_attribute :id, :id
alias_attribute :benefit_desc, :benefit_desc
alias_attribute :benefit, :benefit
alias_attribute :sequence, :sequence
alias_attribute :plan_id, :plan_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+25
View File
@@ -0,0 +1,25 @@
module Baclight
class IdCardSetup < BaclightRecord
self.table_name = 'id_card_setups'
alias_attribute :id, :id
alias_attribute :print_name, :print_name
alias_attribute :network_provider, :network_provider
alias_attribute :card_template, :card_template
alias_attribute :card_color, :card_color
alias_attribute :rx_group_number, :rx_group_number
alias_attribute :pl_plan_key, :pl_plan_key
alias_attribute :has_divisions, :has_divisions
alias_attribute :has_dental, :has_dental
alias_attribute :active, :active
alias_attribute :initialized, :initialized
alias_attribute :employer_id, :employer_id
alias_attribute :network_logo_id, :network_logo_id
alias_attribute :provider_section_id, :provider_section_id
alias_attribute :rx_section_id, :rx_section_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+44
View File
@@ -0,0 +1,44 @@
module Baclight
class Member < BaclightRecord
self.table_name = 'Members'
belongs_to :baclight_employer, class_name: "Baclight::Employer", foreign_key: "employer_id"
scope :active, -> {
where(active: true)
}
# alias_attribute :id, :id
# alias_attribute :name, :name
# alias_attribute :family_id, :family_id
# alias_attribute :mb_member_key, :mb_member_key
# alias_attribute :pb_entity_key, :pb_entity_key
# alias_attribute :pl_plan_key, :pl_plan_key
# alias_attribute :id_card_display_name, :id_card_display_name
# alias_attribute :coverage_class, :coverage_class
# alias_attribute :division, :division
# alias_attribute :dental_plan_key, :dental_plan_key
# alias_attribute :dependents, :dependents
# alias_attribute :employer_id, :employer_id
# alias_attribute :id_card_plan_id, :id_card_plan_id
# alias_attribute :created_at, :created_at
# alias_attribute :updated_at, :updated_at
# def member_belongs_to
# {
# broker_id: baclight_employer&.broker_id,
# carrier_id: baclight_employer&.baclight_broker&.carrier_id
# }
# end
def broker_id
baclight_employer&.broker_id
end
def carrier_id
baclight_employer&.baclight_broker&.carrier_id
end
end
end
+16
View File
@@ -0,0 +1,16 @@
module Baclight
class Provider < BaclightRecord
self.table_name = 'Providers'
alias_attribute :id, :id
alias_attribute :name, :name
alias_attribute :pb_entity_key, :pb_entity_key
alias_attribute :tax_id, :tax_id
alias_attribute :family_id, :family_id
alias_attribute :provider_group_id, :provider_group_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+4
View File
@@ -0,0 +1,4 @@
class BaclightRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :baclight, reading: :baclight }
end
@@ -1,11 +1,11 @@
class BlacklistedToken < ApplicationRecord
class RetiredToken < ApplicationRecord
belongs_to :user
validates :jti, presence: true, uniqueness: true
validates :exp, presence: true
# check if a token is blacklisted
def self.blacklisted?(jti)
# check if a token is retired
def self.retired?(jti)
exists?(jti: jti)
end
+127 -12
View File
@@ -1,17 +1,132 @@
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :recoverable, :rememberable, :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:validatable
include Devise::JWT::RevocationStrategies::JTIMatcher
# associations
has_many :blacklisted_tokens, dependent: :destroy
has_many :refresh_tokens, dependent: :destroy
devise :database_authenticatable, :registerable,
:validatable, :jwt_authenticatable, jwt_revocation_strategy: self
# Include default devise modules. Others available are:
# :recoverable, :rememberable, :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
# role-based authorization
enum :role, { user: 0, admin: 1, moderator: 2 }
# role-based authorization
enum :role, { member: 0, employer: 1, broker: 2, provider: 3, carrier: 4, admin: 5 }
attr_accessor :keychain
attr_accessor :date_of_birth
attr_accessor :last_four_ssn
# validations so your db doesn't turn into a trash can
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, presence: true, length: { minimum: 6 }, if: -> { new_record? || !password.nil? }
validates :role, presence: true
validates :role_id, presence: true
validate :role_entity_exists, on: :create
# after_initialize :keychain
before_validation :sync_role_entity, on: :create
def keychain
@keychain ||= case role
when "member"
if role_entity.present?
# belongs_to = {
# employer_id: role_entity.employer_id,
# broker_id: role_entity&.baclight_employer.broker_id,
# carrier_id:role_entity&.baclight_employer&.baclight_broker&.carrier_id
# }
keys = role_entity.attributes.with_indifferent_access.slice(
:id, :name, :family_id, :mb_member_key, :pb_entity_key, :pl_plan_key
)
keys #.merge(belongs_to)
end
when "employer"
if role_entity.present?
belongs_to = role_entity.joins(broker: :carrier).select(
'brokers.id AS broker_id',
'carriers.id AS carrier_id'
)
keys = role_entity.attributes.with_indifferent_access.slice(
:name, :pl_plan_key, :company_pb_entity_key, :plan_id, :group_number
)
keys.merge(belongs_to)
end
when "broker"
if role_entity.present?
belongs_to = role_entity.joins(:carrier).select(
'carriers.id AS carrier_id'
)
role_entity.attributes.with_indifferent_access.slice(
:name, :id
).merge(belongs_to)
end
when "provider"
if role_entity.present?
role_entity.attributes.with_indifferent_access.slice(
:name, :pb_entity_key, :tax_id, :family_id
)
end
when "carrier"
if role_entity.present?
role_entity.attributes.with_indifferent_access.slice(
:name, :id
)
end
# when "admin"
end
end
private
def role_entity
@role_entity = case role
when "member"
if self.persisted?
Baclight::Member.find_by(pb_entity_key: role_id)
else
find_initial_member
end
when "employer"
Baclight::Employer.find_by(company_pb_entity_key: role_id)
when "broker"
Baclight::Broker.find_by(broker_id: role_id)
when "provider"
Baclight::Provider.find_by(tax_id: role_id)
when "carrier"
Baclight::Carrier.find_by(carrier_id: role_id)
# when "admin"
end
end
def sync_role_entity
if role == "member"
self.name = role_entity.name.split(",").reverse.join(" ").squish
else
self.name = role_entity.name
end
end
def role_entity_exists
if role_entity.blank?
errors.add(:role, "#{role} with id #{role_id} was not found.")
end
if role == "member"
dob = Vhcs::VwmbMember.find_by(pb_entity_key: role_id).date_of_birth
unless dob == date_of_birth
errors.add(:role, "#{role} with id #{role_id} and #{date_of_birth} was not found.")
end
end
end
def find_initial_member
initial_member = Vhcs::VwmbMember.where("RIGHT(SocialSecurityNumber, 4) = ? AND DateOfBirth = ?", last_four_ssn, date_of_birth).first
self.role_id = initial_member&.pb_entity_key
member = Baclight::Member.find_by(pb_entity_key: role_id)
member.presence
end
# validations so your db doesn't turn into a trash can
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, presence: true, length: { minimum: 6 }, if: -> { new_record? || !password.nil? }
end
+103
View File
@@ -0,0 +1,103 @@
module Vhcs
class VwmbMember < VhcsRecord
self.table_name = 'VwmbMember'
alias_attribute :mb_member_key, :MBMemberKey
alias_attribute :pb_entity_key, :PBEntityKey
alias_attribute :pl_plan_key, :PLPlanKey
alias_attribute :mbr_class, :MbrClass
alias_attribute :mbr_type, :MbrType
alias_attribute :mbr_ap_vendor_key, :MbrAPVendorKey
alias_attribute :alt_ap_vendor_key, :AltAPVendorKey
alias_attribute :use_alt_payee, :UseAltPayee
alias_attribute :send_eob_primary, :SendEOBPrimary
alias_attribute :send_eob_dependent, :SendEOBDependent
alias_attribute :send_eob_third_party, :SendEOBThirdParty
alias_attribute :student_flag, :StudentFlag
alias_attribute :disabled_dependent_flag, :DisabledDependentFlag
alias_attribute :is_restricted, :IsRestricted
alias_attribute :third_party_pb_entity_key, :ThirdPartyPBEntityKey
alias_attribute :user_def_1, :UserDef1
alias_attribute :user_def_2, :UserDef2
alias_attribute :family_id, :FamilyID
alias_attribute :sequence_number, :SequenceNumber
alias_attribute :enrollee_type_key, :EnrolleeTypeKey
alias_attribute :enrollee_type, :EnrolleeType
alias_attribute :enrollee_type_value_id, :EnrolleeTypeValueID
alias_attribute :sex_key, :SexKey
alias_attribute :use_primary_address, :UsePrimaryAddress
alias_attribute :birth_date, :BirthDate
alias_attribute :birth_sequence_number, :BirthSequenceNumber
alias_attribute :death_date, :DeathDate
alias_attribute :date_of_birth, :DateOfBirth
alias_attribute :date_of_death, :DateOfDeath
alias_attribute :social_security_number, :SocialSecurityNumber
alias_attribute :hipaaid, :HIPAAID
alias_attribute :company_pb_entity_key, :CompanyPBEntityKey
alias_attribute :entity_type_id, :EntityTypeID
alias_attribute :prefix_id, :PrefixID
alias_attribute :first_name, :FirstName
alias_attribute :middle_name, :MiddleName
alias_attribute :last_name, :LastName
alias_attribute :suffix_id, :SuffixID
alias_attribute :title, :Title
alias_attribute :letter_tag_bit_flags, :LetterTagBitFlags
alias_attribute :full_name_last_name_first, :FullNameLastNameFirst
alias_attribute :policy_number, :PolicyNumber
alias_attribute :send_eob_alt_payee, :SendEOBAltPayee
alias_attribute :send_eob_alt_payee_only, :SendEOBAltPayeeOnly
def attributes
rails_like = {
mb_member_key: self.mb_member_key,
pb_entity_key: self.pb_entity_key,
pl_plan_key: self.pl_plan_key,
mbr_class: self.mbr_class,
mbr_type: self.mbr_type,
mbr_ap_vendor_key: self.mbr_ap_vendor_key,
alt_ap_vendor_key: self.alt_ap_vendor_key,
use_alt_payee: self.use_alt_payee,
send_eob_primary: self.send_eob_primary,
send_eob_dependent: self.send_eob_dependent,
send_eob_third_party: self.send_eob_third_party,
student_flag: self.student_flag,
disabled_dependent_flag: self.disabled_dependent_flag,
is_restricted: self.is_restricted,
third_party_pb_entity_key: self.third_party_pb_entity_key,
user_def_1: self.user_def_1,
user_def_2: self.user_def_2,
family_id: self.family_id,
sequence_number: self.sequence_number,
enrollee_type_key: self.enrollee_type_key,
enrollee_type: self.enrollee_type,
enrollee_type_value_id: self.enrollee_type_value_id,
sex_key: self.sex_key,
use_primary_address: self.use_primary_address,
birth_date: self.birth_date,
birth_sequence_number: self.birth_sequence_number,
death_date: self.death_date,
date_of_birth: self.date_of_birth,
date_of_death: self.date_of_death,
social_security_number: self.social_security_number,
hipaaid: self.hipaaid,
company_pb_entity_key: self.company_pb_entity_key,
entity_type_id: self.entity_type_id,
prefix_id: self.prefix_id,
first_name: self.first_name,
middle_name: self.middle_name,
last_name: self.last_name,
suffix_id: self.suffix_id,
title: self.title,
letter_tag_bit_flags: self.letter_tag_bit_flags,
full_name_last_name_first: self.full_name_last_name_first,
policy_number: self.policy_number,
send_eob_alt_payee: self.send_eob_alt_payee,
send_eob_alt_payee_only: self.send_eob_alt_payee_only,
}
super.merge(rails_like)
end
end
end
+4
View File
@@ -0,0 +1,4 @@
class VhcsRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :vhcs, reading: :vhcs }
end
+53
View File
@@ -0,0 +1,53 @@
# frozen_string_literal: true
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
false
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
class Scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
raise NoMethodError, "You must define #resolve in #{self.class}"
end
private
attr_reader :user, :scope
end
end
+13
View File
@@ -0,0 +1,13 @@
class Baclight::BrokerPolicy < ApplicationPolicy
def employers_list?; true; end
private
def broker_rule?
user.admin? ||
(user.broker? && record.broker_id == user.keychain[:id]) ||
(user.carrier? && record.carrier_id == user.keychain[:id])
end
end
+15
View File
@@ -0,0 +1,15 @@
class Baclight::EmployerPolicy < ApplicationPolicy
def id_cards?; employer_rule?; end
def members_list?; true; end
private
def employer_rule?
user.admin? ||
(user.employer? && record.employer_id == user.keychain[:id]) ||
(user.broker? && record.broker_id == user.keychain[:id]) ||
(user.carrier? && record.carrier_id == user.keychain[:id])
end
end
+22
View File
@@ -0,0 +1,22 @@
class Baclight::MemberPolicy < ApplicationPolicy
def initialize_dashboard?; member_rule?; end
def id_card?; member_rule?; end
def claims?
user.admin? ||
(user.member? && record.id == user.keychain[:id]) ||
(user.carrier? && record.carrier_id == user.keychain[:id])
end
private
def member_rule?
user.admin? ||
(user.member? && record.id == user.keychain[:id]) ||
(user.employer? && record.employer_id == user.keychain[:id]) ||
(user.broker? && record.broker_id == user.keychain[:id]) ||
(user.carrier? && record.carrier_id == user.keychain[:id])
end
end
+18
View File
@@ -0,0 +1,18 @@
class IdCardsPolicy < ApplicationPolicy
# Corresponds to PostController#edit or #update
def member_card?
user.admin? ||
(user.carrier? && record.belongs_to_levels.carrier_id == user.keychain.id) ||
(user.broker? && record.belongs_to_levels.broker_id == user.keychain.id) ||
(user.employer? && record.pl_plan_key == user.keychain.pl_plan_key) ||
(user.member? && record.pb_entity_key == user.keychain.pb_entity_key)
end
# Corresponds to PostController#destroy
def employer_cards?
user.admin? ||
(user.carrier? && record.belongs_to_levels.carrier_id == user.keychain.id) ||
(user.broker? && record.belongs_to_levels.broker_id == user.keychain.id) ||
(user.employer? && record.pl_plan_key == user.keychain.pl_plan_key)
end
end
+14
View File
@@ -0,0 +1,14 @@
class CallStoredProc
def initialize(procedure_name, args = {})
@procedure_name = procedure_name
@args = args
end
def call
params_sql = @args.map { |key, value| "@#{key} = :#{key}" }.join(', ')
sql_template = "EXEC #{@procedure_name} #{params_sql}"
sanitized_sql = VhcsRecord.send(:sanitize_sql_array, [sql_template, @args])
VhcsRecord.connection.exec_query(sanitized_sql)
end
end
@@ -0,0 +1,41 @@
module EmployersService
class IdCards
def initialize(pl_plan_key)
@employer = Baclight::Employer.find_by(pl_plan_key: pl_plan_key)
if @employer.present?
@pl_plan_key = pl_plan_key
else
raise ArgumentError, "Member not found."
end
end
def call
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/employer_cards/#{@pl_plan_key}"
}
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/zip' },
stream_body: true
)
if response.code == 200
# content_disposition = response.headers['Content-Disposition']
# {
# zip_file: response.body,
# filename: content_disposition[/filename="?([^"]*)"?/, 1]
# }
response
else
nil
end
end
end
end
+33
View File
@@ -0,0 +1,33 @@
class MemberClaimsService
def initialize(pb_entity_key)
@member = Baclight::Member.find_by(pb_entity_key: pb_entity_key)
if @member.present?
@pl_plan_key = @member.pl_plan_key
@family_id = @member.family_id
else
raise ArgumentError, "Member not found."
end
end
def call
args = {
PLPlanKey: @pl_plan_key,
FamilyId: @family_id,
ProviderTaxId: "",
UserID: "JASONJ"
}
claims_headers = CallStoredProc.new("CPFindClaim", args).call
recent_claims_headers = claims_headers.sort_by { |ch| ch['IncurDate'].to_date }.reverse.first(6)
recent_claims_headers.map { |ch| { claim_number: ch['CPHeaderKey'], visit_date: ch['IncurDate'].strftime("%m-%d-%Y"), claim_status: ch['AdjudicatedStatusShortDesc'], patient_name: ch['FullName'], provider_name: ch['ProviderCompany']} }
end
end
# claimHeaders = _vContext.ClaimHeader.FromSql("dbo.CPFindClaim
# @PLPlanKey = {0}, @CSCaseKey = {1}, @PAPriorAuthKey = {2}, @FromDate = {3}, @ToDate = {4}, @FamilyID = {5}, @FirstName = {6}, @LastName = {7}, @SequenceNumber = {8}, @PBEntityKey = {9}, @ProviderIdentifierCode = {10}, @ProviderCompanyName = {11}, @ProviderTaxID = {12}, @HeaderStatusValueID = {13}, @AdjudicatedStatusValueID = {14}, @EventUSUserKey = {15}, @IncludeRestricted = {16}, @ClaimTypeValueID = {17}, @ClaimSource = {18}, @ReceivedFromDate = {19}, @ReceivedToDate = {20}, @DCN = {21}, @SSN = {22}, @SSN_IncFamily = {23}, @SearchAllIDs = {24}, @UserID = {25}, @ExecuteOrDisplay = {26} ",
# PlanKey, 0, 0, FromDate, ToDate, FamilyId, "", "", -1, 0, "", "", ProviderTaxId, 0, 0, 0, 0, 0, 2, null, null, null, null, 0, 0, "DAVIDH", 1)
+41
View File
@@ -0,0 +1,41 @@
module MembersService
class Claims
def initialize(entity, recent = false)
if entity.is_a?(Integer)
@member = Baclight::Member.find_by(pb_entity_key: entity)
else
@member = entity
end
if @member.present?
@pl_plan_key = @member.pl_plan_key
@family_id = @member.family_id
@recent = recent
else
raise ArgumentError, "Member not found."
end
end
def call
args = {
PLPlanKey: @pl_plan_key,
FamilyId: @family_id,
ProviderTaxId: "",
UserID: "JASONJ"
}
claims_headers = CallStoredProc.new("CPFindClaim", args).call
ordered_claims_headers = claims_headers.sort_by { |ch| ch['IncurDate'].to_date }.reverse
ordered_claims_headers = ordered_claims_headers.first(6) if @recent
ordered_claims_headers.map { |ch| { claim_number: ch['CPHeaderKey'], visit_date: ch['IncurDate'].strftime("%m-%d-%Y"), claim_status: ch['AdjudicatedStatusShortDesc'], patient_name: ch['FullName'], provider_name: ch['ProviderCompany']} } || []
end
end
end
# claimHeaders = _vContext.ClaimHeader.FromSql("dbo.CPFindClaim
# @PLPlanKey = {0}, @CSCaseKey = {1}, @PAPriorAuthKey = {2}, @FromDate = {3}, @ToDate = {4}, @FamilyID = {5}, @FirstName = {6}, @LastName = {7}, @SequenceNumber = {8}, @PBEntityKey = {9}, @ProviderIdentifierCode = {10}, @ProviderCompanyName = {11}, @ProviderTaxID = {12}, @HeaderStatusValueID = {13}, @AdjudicatedStatusValueID = {14}, @EventUSUserKey = {15}, @IncludeRestricted = {16}, @ClaimTypeValueID = {17}, @ClaimSource = {18}, @ReceivedFromDate = {19}, @ReceivedToDate = {20}, @DCN = {21}, @SSN = {22}, @SSN_IncFamily = {23}, @SearchAllIDs = {24}, @UserID = {25}, @ExecuteOrDisplay = {26} ",
# PlanKey, 0, 0, FromDate, ToDate, FamilyId, "", "", -1, 0, "", "", ProviderTaxId, 0, 0, 0, 0, 0, 2, null, null, null, null, 0, 0, "DAVIDH", 1)
+41
View File
@@ -0,0 +1,41 @@
module MembersService
class IdCard
def initialize(member, layout)
@member = member
if @member.present?
@pb_entity_key = @member.pb_entity_key
@layout = layout
else
raise ArgumentError, "Member not found."
end
end
def call
url_components = {
host: ENV["BACLIGHT_SERVER_HOST"],
port: ENV["BACLIGHT_SERVER_PORT"],
path: "/api/v1/web_id_cards/member_card/#{@pb_entity_key}/#{@layout}"
}
response = HTTParty.get(
URI::HTTP.build(url_components),
headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/pdf' },
stream_body: true
)
if response.code == 200
# content_disposition = response.headers['Content-Disposition']
# {
# pdf_file: response.body,
# filename: content_disposition[/filename="?([^"]*)"?/, 1]
# }
response
else
nil
end
end
end
end
@@ -0,0 +1,24 @@
module MembersService
class InitializeDashboard
def initialize(member)
@member = member
unless @member.present?
raise ArgumentError, "Member not found."
end
end
def call
plan_benefits = MembersService::PlanBenefits.new(@member).call
network_provider = MembersService::NetworkProvider.new(@member).call
recent_claims = MembersService::Claims.new(@member, true).call
{
network_provider: network_provider,
plan_benefits: plan_benefits,
recent_claims: recent_claims
}
end
end
end
@@ -0,0 +1,18 @@
module MembersService
class NetworkProvider
def initialize(member)
@member = member
if @member.present?
@pl_plan_key = @member.pl_plan_key
else
raise ArgumentError, "Member not found."
end
end
def call
Baclight::IdCardSetup.find_by(pl_plan_key: @pl_plan_key).network_provider
end
end
end
@@ -0,0 +1,20 @@
module MembersService
class PlanBenefits
def initialize(member)
@member = member
if @member.present?
@plan_id = @member.id_card_plan_id
else
raise ArgumentError, "Member not found."
end
end
def call
Baclight::IdCardPlan.joins(:baclight_id_card_plan_benefits)
.select('id_card_plans.id, id_card_plans.title, id_card_plan_benefits.id, id_card_plan_benefits.sequence, id_card_plan_benefits.benefit, id_card_plan_benefits.benefit_desc')
.where(id: @plan_id)
.distinct
end
end
end