Skip to content

Commit

Permalink
perf updates to cv3 payload generation (#4016)
Browse files Browse the repository at this point in the history
* perf updates to cv3 payload generation

* initial round of spec fixes

* spec fixes

* spec fixes

---------

Co-authored-by: Sai Praveen Gudimetla <[email protected]>
Co-authored-by: Trey <[email protected]>
  • Loading branch information
3 people authored Jul 26, 2024
1 parent 6017619 commit d8094b6
Show file tree
Hide file tree
Showing 24 changed files with 250 additions and 100 deletions.
2 changes: 1 addition & 1 deletion app/domain/operations/pay_now/care_first/embedded_xml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def call(enrollment)

def transform_enrollment(enrollment)
cv3_enrollment = Operations::Transformers::HbxEnrollmentTo::Cv3HbxEnrollment.new.call(enrollment)
cv3_enrollment.success? ? cv3_enrollment : Failure("unable to transform hbx enrollment #{hbx_enrollment.hbx_id} due to #{cv3_enrollment.failure}")
cv3_enrollment.success? ? cv3_enrollment : Failure("unable to transform hbx enrollment #{enrollment.hbx_id} due to #{cv3_enrollment.failure}")
end

def transform_member_array(enrollment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ def fetch_member_premium(rating_silver_products_hash, tax_household_member, effe
# min_age = family.family_members.map {|fm| fm.age_on(TimeKeeper.date_of_record) }.min
# benchmark_product_model = EnrollRegistry[:enroll_app].setting(:benchmark_product_model).item

health_products = rating_silver_products_hash[:products].where(kind: :health)
health_products = rating_silver_products_hash[:products].select { |product| product.kind == :health }
premium_hash = Operations::Products::FetchSlcspPremiumForTaxHouseholdMember.new.call(
{
products: health_products,
effective_date: effective_date,
rating_area_id: rating_silver_products_hash[:rating_area_id],
rating_area_exchange_provided_code: rating_silver_products_hash[:rating_area_exchange_provided_code],
tax_household_member: tax_household_member
}
)
Expand Down
10 changes: 6 additions & 4 deletions app/domain/operations/products/fetch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,16 @@ def fetch_member_premiums(rating_silver_products, family, effective_date)
rating_silver_products.each_pair do |hbx_ids, payload|
member_premiums[hbx_ids] = {}

health_products = payload[:products].where(kind: :health)
premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: health_products, family: family, effective_date: effective_date, rating_area_id: payload[:rating_area_id]})
health_products = payload[:products].select { |product| product.kind == :health }
premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: health_products, family: family, effective_date: effective_date,
rating_area_exchange_provided_code: payload[:rating_area_exchange_provided_code] })

return Failure("unable to fetch health only premiums for - #{hbx_ids}") if premiums.failure?
member_premiums[hbx_ids][:health_only] = premiums.value!

if benchmark_product_model == :health_and_dental && min_age < 19

premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: payload[:products], family: family, effective_date: effective_date, rating_area_id: payload[:rating_area_id]})
premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: payload[:products], family: family, effective_date: effective_date, rating_area_exchange_provided_code: payload[:rating_area_exchange_provided_code]})

return Failure("unable to fetch health only premiums for - #{hbx_ids}") if premiums.failure?
member_premiums[hbx_ids][:health_and_dental] = premiums.value!
Expand All @@ -88,7 +89,8 @@ def fetch_member_premiums(rating_silver_products, family, effective_date)
next unless benchmark_product_model == :health_and_ped_dental && min_age < 19
health_and_ped_dental_products = payload[:products] # TODO: - filter child only ped dental products.

premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: health_and_ped_dental_products, family: family, effective_date: effective_date, rating_area_id: payload[:rating_area_id]})
premiums = Operations::Products::FetchSilverProductPremiums.new.call({products: health_and_ped_dental_products, family: family, effective_date: effective_date,
rating_area_exchange_provided_code: payload[:rating_area_exchange_provided_code]})

return Failure("unable to fetch health only premiums for - #{hbx_ids}") if premiums.failure?
member_premiums[hbx_ids][:health_and_ped_dental] = premiums.value!
Expand Down
31 changes: 10 additions & 21 deletions app/domain/operations/products/fetch_silver_product_premiums.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ class FetchSilverProductPremiums
include Dry::Monads[:do, :result]

# @param [Date] effective_date
# @param [RatingArea] rating_area_id
# @param [RatingArea] rating_area_exchange_provided_code
# @param [Family] family
# @param [Product] products
# @param [FamilyMember] family_member_id Passing in family_member_id will only return premiums for that particular member
def call(params)
values = yield validate(params)
family_members = yield fetch_family_members(values[:family], values[:family_member_id])
product_premiums = yield fetch_product_premiums(values[:products], family_members, values[:effective_date], values[:rating_area_id].to_s)
product_premiums = yield fetch_product_premiums(values[:products], family_members, values[:effective_date], values[:rating_area_exchange_provided_code].to_s)

Success(product_premiums)
end
Expand All @@ -25,14 +25,15 @@ def validate(params)
return Failure('Missing Products') if params[:products].blank?
return Failure('Missing Family') if params[:family].blank?
return Failure('Missing Effective Date') if params[:effective_date].blank?
return Failure('Missing rating area id') if params[:rating_area_id].blank?
return Failure('Missing rating area exchange code') if params[:rating_area_exchange_provided_code].blank?

Success(params)
end

def fetch_family_members(family, family_member_id)
family_members = family.family_members.active
family_members = family.family_members.where(id: BSON::ObjectId(family_member_id)) if family_member_id
members = family.family_members
family_members = members.active
family_members = members.where(id: BSON::ObjectId(family_member_id)) if family_member_id

if family_members.present?
Success(family_members)
Expand All @@ -41,7 +42,7 @@ def fetch_family_members(family, family_member_id)
end
end

def fetch_product_premiums(products, family_members, effective_date, rating_area_id)
def fetch_product_premiums(products, family_members, effective_date, rating_area_exchange_provided_code)
member_premiums = family_members.inject({}) do |member_result, family_member|
age = family_member.age_on(effective_date)
hbx_id = family_member.hbx_id
Expand All @@ -50,22 +51,10 @@ def fetch_product_premiums(products, family_members, effective_date, rating_area
products.inject([]) do |result, product|
variant_id = product.hios_id.split('-')[1]
next result if variant_id.present? && variant_id != '01'
premium_table = product.premium_tables.where({
:rating_area_id => rating_area_id,
:'effective_period.min'.lte => effective_date,
:'effective_period.max'.gte => effective_date
}).first
cost = ::BenefitMarkets::Products::ProductRateCache.lookup_rate(product, effective_date, age, rating_area_exchange_provided_code)

result << { cost: (cost * product.ehb).round(2), product_id: product.id, member_identifier: hbx_id, monthly_premium: (cost * product.ehb).round(2) } if cost.present?

tuple = premium_table.premium_tuples.where(age: age).first
if tuple.blank?
tuple_ages = premium_table.premium_tuples.map(&:age)
min_age = tuple_ages.min
max_age = tuple_ages.max
age = min_age if age < min_age
age = max_age if age > max_age
tuple = premium_table.premium_tuples.where(age: age).first
end
result << { cost: (tuple.cost * product.ehb).round(2), product_id: product.id, member_identifier: hbx_id, monthly_premium: (tuple.cost * product.ehb).round(2) } if tuple.present?
result
end
member_result[hbx_id] = product_hash.sort_by {|tuple_hash| tuple_hash[:cost]}
Expand Down
27 changes: 21 additions & 6 deletions app/domain/operations/products/fetch_silver_products.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ def call(params)
rating_area = yield find_rating_area(values[:effective_date], values[:address])
service_areas = yield find_service_areas(values[:effective_date], values[:address])
query = yield query_criteria(rating_area.id, service_areas.map(&:id), values[:effective_date])
products = yield fetch_products(query, values)
payload = yield construct_payload(products, rating_area.id)
cache_key = yield construct_cache_key(rating_area.id, service_areas.map(&:id), values[:effective_date])
products = yield fetch_products(cache_key, query, values)
payload = yield construct_payload(products, rating_area.id, rating_area.exchange_provided_code)

Success(payload)
end
Expand Down Expand Up @@ -58,17 +59,31 @@ def query_criteria(rating_area_id, service_area_ids, effective_date)
})
end

def fetch_products(query_criteria, values)
products = BenefitMarkets::Products::Product.where(query_criteria)
def construct_cache_key(rating_area_id, service_area_ids, effective_date)
Success({
:metal_level_kinds => [:silver, :dental],
:rating_area_id => rating_area_id.to_s,
:service_area_ids => service_area_ids.map(&:to_s),
:active_year => effective_date.year,
:benefit_market_kind => :aca_individual
})
end

def fetch_products(cache_key, query_criteria, values)
products = Rails.cache.fetch(cache_key.to_json, expire_in: 12.hours) do
BenefitMarkets::Products::Product.where(query_criteria).to_a
end

if products.present?
Success(products)
else
Failure("Could Not find any Products for the given criteria - effective_date: #{values[:effective_date]}, county: #{values[:address].county}, zip: #{values[:address].zip}")
end
end

def construct_payload(products, rating_area_id)
Success({products: products, rating_area_id: rating_area_id})
def construct_payload(products, rating_area_id, rating_area_exchange_provided_code)
Success({products: products, rating_area_id: rating_area_id,
rating_area_exchange_provided_code: rating_area_exchange_provided_code})
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ class FetchSlcspPremiumForTaxHouseholdMember
include Dry::Monads[:do, :result]

# @param [Date] effective_date
# @param [RatingArea] rating_area_id
# @param [RatingArea] rating_area_exchange_provided_code
# @param [TaxHouseholdMember] tax_household_member
# @param [Product] products
def call(params)
values = yield validate(params)
product_premiums = yield fetch_product_premiums(values[:products], values[:tax_household_member], values[:effective_date], values[:rating_area_id].to_s)
product_premiums = yield fetch_product_premiums(values[:products], values[:tax_household_member], values[:effective_date], values[:rating_area_exchange_provided_code].to_s)

Success(product_premiums)
end
Expand All @@ -23,12 +23,12 @@ def validate(params)
return Failure('Missing Products') if params[:products].blank?
return Failure('Missing TaxHouseholdMember') if params[:tax_household_member].blank?
return Failure('Missing Effective Date') if params[:effective_date].blank?
return Failure('Missing rating area id') if params[:rating_area_id].blank?
return Failure('Missing rating area exchange code') if params[:rating_area_exchange_provided_code].blank?

Success(params)
end

def fetch_product_premiums(products, tax_household_member, effective_date, rating_area_id)
def fetch_product_premiums(products, tax_household_member, effective_date, rating_area_exchange_provided_code)
family_member = tax_household_member.family_member

product_hash = Operations::Products::FetchSilverProductPremiums.new.call(
Expand All @@ -37,15 +37,15 @@ def fetch_product_premiums(products, tax_household_member, effective_date, ratin
family: tax_household_member.family,
family_member_id: family_member.id,
effective_date: effective_date,
rating_area_id: rating_area_id
rating_area_exchange_provided_code: rating_area_exchange_provided_code
}
)

if product_hash.success? && product_hash.success[family_member.hbx_id]
values = product_hash.success[family_member.hbx_id]
Success(values[1] || values[0])
else
Failure("Unable to determine SLCSP premium for tax_household_member: #{tax_household_member.id} for effective_date: #{effective_date} and rating_area: #{rating_area_id}")
Failure("Unable to determine SLCSP premium for tax_household_member: #{tax_household_member.id} for effective_date: #{effective_date} and rating_area: #{rating_area_exchange_provided_code}")
end
end
end
Expand Down
23 changes: 14 additions & 9 deletions app/domain/operations/transformers/family_to/cv3_family.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def call(family, exclude_applications = false, *args)

private

def construct_payload(family, exclude_applications, args)
def construct_payload(family, _exclude_applications, _args)
@family_hbx_id = family.hbx_assigned_id.to_s
payload = {
hbx_id: @family_hbx_id,
Expand All @@ -49,25 +49,30 @@ def construct_payload(family, exclude_applications, args)
# broker_accounts = transform_broker_accounts(family.broker_accounts), #TO DO
# updated_by: construct_updated_by(updated_by)
}
payload.merge!(eligibility_determination: transform_eligibility_determinination(family)) if family.eligibility_determination.present?
eligibility_determination = family.eligibility_determination
irs_groups = family.irs_groups
tax_household_groups = family.tax_household_groups

payload.merge!(eligibility_determination: transform_eligibility_determinination(eligibility_determination)) if eligibility_determination.present?
payload.merge!(min_verification_due_date: family.min_verification_due_date) if family.min_verification_due_date.present?
payload.merge!(irs_groups: transform_irs_groups(family.irs_groups)) if family.irs_groups.present?
payload.merge!(irs_groups: transform_irs_groups(irs_groups)) if irs_groups.present?
payload.merge!(households: @transformed_households) if @transformed_households.present?
payload.merge!(tax_household_groups: transform_tax_household_groups(family.tax_household_groups)) if family.tax_household_groups.present?
payload.merge!(tax_household_groups: transform_tax_household_groups(tax_household_groups)) if tax_household_groups.present?

Success(payload)
end

def transform_eligibility_determinination(family)
return {} if family.eligibility_determination.nil?
family.eligibility_determination.serializable_cv_hash
def transform_eligibility_determinination(eligibility_determination)
return {} if eligibility_determination.nil?
eligibility_determination.serializable_cv_hash
end

def transform_applications(family, exclude_applications)
return Success(nil) unless EnrollRegistry.feature_enabled?(:financial_assistance)
return Success([]) if exclude_applications

applications = ::FinancialAssistance::Application.where(family_id: family.id).determined
applications = ::FinancialAssistance::Application.only(:aasm_state, :family_id, :effective_date, :assistance_year, :renewal_base_year, :years_to_renew, :is_ridp_verified, :is_renewal_authorized, :us_state, :hbx_id, :submitted_at,
:applicants, :eligibility_determinations,:relationships, :'workflow_state_transitions.from_state', :full_medicaid_determination).where(family_id: family.id).determined
transformed_applications = applications.collect do |application|
::FinancialAssistance::Operations::Applications::Transformers::ApplicationTo::Cv3Application.new.call(application)
end.compact
Expand All @@ -92,7 +97,7 @@ def transform_special_enrollment_periods(special_enrollment_periods)
csl_num: period.csl_num,
market_kind: period.market_kind,
admin_flag: period.admin_flag,
timestamp: {created_at: period.created_at.to_datetime, modified_at: period.updated_at.to_datetime}
timestamp: { created_at: period.created_at.to_datetime, modified_at: period.updated_at.to_datetime }
}
sep_hash.merge!(next_poss_effective_date: period.next_poss_effective_date) if period.next_poss_effective_date.present?
sep_hash.merge!(option1_date: period.option1_date) if period.option1_date.present?
Expand Down
Loading

0 comments on commit d8094b6

Please sign in to comment.