diff --git a/app/models/payroll_run.rb b/app/models/payroll_run.rb index 2d5a4992b..86b30cc8a 100644 --- a/app/models/payroll_run.rb +++ b/app/models/payroll_run.rb @@ -56,31 +56,42 @@ def payments_count class LineItem < Struct.new(:id, :award_amount, keyword_init: true); end def line_items(policy, filter: :all) - scope = Claim - .select( - " - DISTINCT(claims.id), - COALESCE(topups.award_amount, eligibilities.award_amount) AS award_amount - " - ) - .with_award_amounts - .left_joins(payments: :topups) - .joins(payments: :payroll_run) - .where(payroll_runs: {id: id}) + policies = if policy == :all + Policies::POLICIES + else + [policy] + end - scope = scope.by_policy(policy) unless policy == :all + claims_topped_up_in_payroll_run = Claim + .select("claims.id AS id, topups.award_amount AS award_amount") + .joins(topups: :payment) + .where(payments: {payroll_run_id: id}) + .by_policies(policies) + + claims_without_topups_in_payroll_run = Claim + .select("claims.id AS id, eligibilities.award_amount AS award_amount") + .with_award_amounts + .joins(:payments) + .where(payments: {payroll_run_id: id}) + .where.not(id: claims_topped_up_in_payroll_run.reselect(:id)) + .by_policies(policies) - case filter + sql = case filter when :claims - scope = scope.where(topups: {id: nil}) + claims_without_topups_in_payroll_run.to_sql when :topups - scope = scope.where.not(topups: {id: nil}) + claims_topped_up_in_payroll_run.to_sql + else + [ + claims_without_topups_in_payroll_run.to_sql, + claims_topped_up_in_payroll_run.to_sql + ].join("\nUNION\n") end # Claim delegates it's award amount to eligibility, so we want to return # a non claim object ensuring the award amount is from the topup if there # is one - ActiveRecord::Base.connection.execute(scope.to_sql).map(&LineItem.method(:new)) + ActiveRecord::Base.connection.execute(sql).map(&LineItem.method(:new)) end def ensure_no_payroll_run_this_month diff --git a/spec/models/payroll_run_spec.rb b/spec/models/payroll_run_spec.rb index c28550c27..2fd349987 100644 --- a/spec/models/payroll_run_spec.rb +++ b/spec/models/payroll_run_spec.rb @@ -197,6 +197,138 @@ ).to eq(204) # 103 + 101 end end + + it "handles claims that have topups in multiple payroll runs" do + claim_1 = create( + :claim, + :approved, + policy: Policies::EarlyCareerPayments, + eligibility_attributes: { + award_amount: 1 + } + ) + + claim_2 = create( + :claim, + :approved, + policy: Policies::EarlyCareerPayments, + eligibility_attributes: { + award_amount: 7 + }, + date_of_birth: claim_1.date_of_birth, + student_loan_plan: claim_1.student_loan_plan, + bank_sort_code: claim_1.bank_sort_code, + bank_account_number: claim_1.bank_account_number, + building_society_roll_number: claim_1.building_society_roll_number, + national_insurance_number: claim_1.national_insurance_number + ) + + first_payroll_run = nil + + travel_to 2.month.ago do + first_payroll_run = create(:payroll_run) + + create( + :payment, + claims: [claim_1], + payroll_run: first_payroll_run + ) + end + + second_payroll_run = nil + + travel_to 1.month.ago do + second_payroll_run = create(:payroll_run) + + create( + :payment, + claims: [claim_1, claim_2], + topups: [create(:topup, claim: claim_1, award_amount: 3)], + payroll_run: second_payroll_run + ) + end + + third_payroll_run = create(:payroll_run) + + create( + :payment, + claims: [claim_1], + topups: [create(:topup, claim: claim_1, award_amount: 5)], + payroll_run: third_payroll_run + ) + + expect( + first_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments) + ).to eq(1) + + expect( + first_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(1) + + expect( + first_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(0) + + expect( + first_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments) + ).to eq(1) + + expect( + first_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(1) + + expect( + first_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(0) + + expect( + second_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments) + ).to eq(10) # topup 3 + claim 7 + + expect( + second_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(7) + + expect( + second_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(3) + + expect( + second_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments) + ).to eq(2) # topup for claim 1 + claim 2 + + expect( + second_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(1) + + expect( + second_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(1) + + expect( + third_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments) + ).to eq(5) + + expect( + third_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(0) + + expect( + third_payroll_run.total_claim_amount_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(5) + + expect( + third_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments) + ).to eq(1) + + expect( + third_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :claims) + ).to eq(0) + + expect( + third_payroll_run.number_of_claims_for_policy(Policies::EarlyCareerPayments, filter: :topups) + ).to eq(1) + end end describe ".this_month" do