diff --git a/app/lib/efile/az/az140_calculator.rb b/app/lib/efile/az/az140_calculator.rb index af77b5512a..2a1ca4926b 100644 --- a/app/lib/efile/az/az140_calculator.rb +++ b/app/lib/efile/az/az140_calculator.rb @@ -41,8 +41,8 @@ def calculate set_line(:AZ140_LINE_14, :calculate_line_14) set_line(:AZ140_LINE_19, :calculate_line_19) set_line(:AZ140_LINE_28, :calculate_line_28) - set_line(:AZ140_LINE_29A, :calculate_line_29A) - set_line(:AZ140_LINE_29B, :calculate_line_29B) + set_line(:AZ140_LINE_29A, :calculate_line_29a) + set_line(:AZ140_LINE_29B, :calculate_line_29b) set_line(:AZ140_LINE_30, @direct_file_data, :fed_taxable_ssb) set_line(:AZ140_LINE_31, :calculate_line_31) set_line(:AZ140_LINE_32, :calculate_line_32) @@ -119,14 +119,22 @@ def calculate_line_28 @intake.direct_file_json_data.interest_reports.sum(&:interest_on_government_bonds).round end - def calculate_line_29A + def calculate_line_29a # total subtraction amount for pensions up to the maximum of $2,500 each for primary and spouse - 0 + primary_pension_amount = @intake.sum_1099_r_followup_type_for_filer(:primary, :income_source_pension_plan?) + primary_max_allowed_subtraction = [primary_pension_amount, 2500].min + return primary_max_allowed_subtraction unless @intake.filing_status_mfj? + + spouse_pension_amount = @intake.sum_1099_r_followup_type_for_filer(:spouse, :income_source_pension_plan?) + [primary_max_allowed_subtraction, [spouse_pension_amount, 2500].min].sum end - def calculate_line_29B + def calculate_line_29b # total subtraction amount for uniformed services - 0 + primary_uniformed_retirement_amount = @intake.sum_1099_r_followup_type_for_filer(:primary, :income_source_uniformed_services?) + return primary_uniformed_retirement_amount unless @intake.filing_status_mfj? + + [primary_uniformed_retirement_amount, @intake.sum_1099_r_followup_type_for_filer(:spouse, :income_source_uniformed_services?)].sum end def calculate_line_31 diff --git a/app/lib/efile/line_data.yml b/app/lib/efile/line_data.yml index dd58a1254b..dc890c9f48 100644 --- a/app/lib/efile/line_data.yml +++ b/app/lib/efile/line_data.yml @@ -17,9 +17,9 @@ AZ140_LINE_19: AZ140_LINE_28: label: '28 Interest on US obligations such as Savings Bonds and Treasury Bills included in the AZ Column' AZ140_LINE_29A: - label: '29A total subtraction amount for pensions up to the maximum of $2,500 each for primary and spouse.' + label: '29a total subtraction amount for pensions up to the maximum of $2,500 each for primary and spouse.' AZ140_LINE_29B: - label: "29B Total subtraction amount for benefits, annuities, and pensions for retired/retainer pay of uniformed services" + label: "29b Total subtraction amount for benefits, annuities, and pensions for retired/retainer pay of uniformed services" AZ140_LINE_30: label: '30 U.S. Social Security or Railroad Retirement Act benefits included as income on your federal return (taxable amount)' AZ140_LINE_31: diff --git a/app/models/state_file_base_intake.rb b/app/models/state_file_base_intake.rb index b32604b2c2..7959dc453c 100644 --- a/app/models/state_file_base_intake.rb +++ b/app/models/state_file_base_intake.rb @@ -236,6 +236,22 @@ def spouse Person.new(self, :spouse) end + def filer_1099_rs(primary_or_spouse) + state_file1099_rs.filter do |state_file_1099_r| + state_file_1099_r.recipient_ssn == send(primary_or_spouse).ssn + end + end + + def sum_1099_r_followup_type_for_filer(primary_or_spouse, followup_type) + filer_1099_rs(primary_or_spouse).sum do |state_file_1099_r| + if state_file_1099_r.state_specific_followup&.send(followup_type) + state_file_1099_r.taxable_amount&.round + else + 0 + end + end + end + def ask_for_signature_pin? false end diff --git a/app/models/state_file_md_intake.rb b/app/models/state_file_md_intake.rb index 8a8e143152..e38ec816b8 100644 --- a/app/models/state_file_md_intake.rb +++ b/app/models/state_file_md_intake.rb @@ -215,22 +215,6 @@ def address end end - def filer_1099_rs(primary_or_spouse) - state_file1099_rs.filter do |state_file_1099_r| - state_file_1099_r.recipient_ssn == send(primary_or_spouse).ssn - end - end - - def sum_1099_r_followup_type_for_filer(primary_or_spouse, followup_type) - filer_1099_rs(primary_or_spouse).sum do |state_file_1099_r| - if state_file_1099_r.state_specific_followup&.send(followup_type) - state_file_1099_r.taxable_amount&.round - else - 0 - end - end - end - def sum_two_1099_r_followup_types_for_filer(primary_or_spouse, income_source, service_type) filer_1099_rs(primary_or_spouse).sum do |state_file_1099_r| state_specific_followup = state_file_1099_r.state_specific_followup diff --git a/spec/controllers/state_file/questions/az_review_controller_spec.rb b/spec/controllers/state_file/questions/az_review_controller_spec.rb index dcca22c5c4..ed20889e03 100644 --- a/spec/controllers/state_file/questions/az_review_controller_spec.rb +++ b/spec/controllers/state_file/questions/az_review_controller_spec.rb @@ -84,8 +84,8 @@ intake.direct_file_data.fed_agi = 23_112 intake.direct_file_data.fed_taxable_ssb = 1_000 allow_any_instance_of(StateFileAzIntake).to receive(:total_exemptions).and_return(25) - allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29A).and_return(5) - allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29B).and_return(10) + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29a).and_return(5) + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29b).and_return(10) allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_31).and_return(15) allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_32).and_return(20) allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_42).and_return(30) diff --git a/spec/lib/efile/az/az140_calculator_spec.rb b/spec/lib/efile/az/az140_calculator_spec.rb index 877d3b7784..fde23a8bb1 100644 --- a/spec/lib/efile/az/az140_calculator_spec.rb +++ b/spec/lib/efile/az/az140_calculator_spec.rb @@ -124,6 +124,124 @@ end end + describe "Line 29a" do + context "has qualifying pension plan" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).and_call_original + end + + context "primary has pension plan amount over 2500" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_pension_plan?).and_return 10_000 + end + + it "returns max subtraction allowed (2500)" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29A].value).to eq(2500) + end + end + + context "primary has pension plan amount under 2500" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_pension_plan?).and_return 2455 + end + + it "returns primary pension plan amount" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29A].value).to eq(2455) + end + end + + context "mfj" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:filing_status_mfj?).and_return true + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_pension_plan?).and_return 100 + end + + context "spouse has pension plan amount over 2500" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:spouse, :income_source_pension_plan?).and_return 2501 + end + + it "returns max subtraction allowed (2500) + primary pension subtraction" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29A].value).to eq(2600) + end + end + + context "spouse has pension plan amount under 2500" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:spouse, :income_source_pension_plan?).and_return 2499 + end + + it "returns max subtraction allowed (2500) + primary pension subtraction" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29A].value).to eq(2599) + end + end + end + end + + describe "Line 29b" do + context "has retirement income from uniformed services" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).and_call_original + end + + context "single" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_uniformed_services?).and_return 199 + end + + it "returns sum of uniformed services retirement income" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29B].value).to eq(199) + end + end + + context "mfj" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:filing_status_mfj?).and_return true + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_uniformed_services?).and_return 100 + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:spouse, :income_source_uniformed_services?).and_return 300 + end + + it "returns sum of both retirement incomes" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29B].value).to eq(400) + end + end + end + + context "has no qualifying retirement income from uniformed services" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).and_call_original + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_uniformed_services?).and_return 0 + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:spouse, :income_source_uniformed_services?).and_return 0 + end + + it "returns 0" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29B].value).to eq(0) + end + end + end + + + context "has qualifying no qualifying pension plan" do + before do + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).and_call_original + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:primary, :income_source_uniformed_services?).and_return 0 + allow_any_instance_of(StateFileAzIntake).to receive(:sum_1099_r_followup_type_for_filer).with(:spouse, :income_source_uniformed_services?).and_return 0 + end + + it "returns 0" do + instance.calculate + expect(instance.lines[:AZ140_LINE_29B].value).to eq(0) + end + end + end + describe "Line 35" do before do intake.direct_file_data.fed_taxable_ssb = 100 @@ -131,8 +249,8 @@ it "subtracts lines 24 through 34c from line 19" do allow(instance).to receive(:calculate_line_19).and_return 700 allow(instance).to receive(:calculate_line_28).and_return 100 - allow(instance).to receive(:calculate_line_29A).and_return 100 - allow(instance).to receive(:calculate_line_29B).and_return 100 + allow(instance).to receive(:calculate_line_29a).and_return 100 + allow(instance).to receive(:calculate_line_29b).and_return 100 allow(instance).to receive(:calculate_line_31).and_return 100 allow(instance).to receive(:calculate_line_32).and_return 100 instance.calculate diff --git a/spec/lib/pdf_filler/az140_pdf_spec.rb b/spec/lib/pdf_filler/az140_pdf_spec.rb index 907787a646..e0f9b4a98c 100644 --- a/spec/lib/pdf_filler/az140_pdf_spec.rb +++ b/spec/lib/pdf_filler/az140_pdf_spec.rb @@ -33,6 +33,18 @@ end end + context "with retirement income" do + before do + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29a).and_return 102 + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29b).and_return 233 + end + + it "fills the fields correctly" do + expect(pdf.hash_for_pdf["29a"]).to eq "102" + expect(pdf.hash_for_pdf["29b"]).to eq "233" + end + end + context 'Nonrefundable Credits from Arizona Form 301, Part 2, line 62' do before do allow_any_instance_of(Efile::Az::Az301Calculator).to receive(:calculate_line_60).and_return 100 diff --git a/spec/lib/submission_builder/ty2022/states/az/az_return_xml_spec.rb b/spec/lib/submission_builder/ty2022/states/az/az_return_xml_spec.rb index fc0c6f0297..dbc5cb35d0 100644 --- a/spec/lib/submission_builder/ty2022/states/az/az_return_xml_spec.rb +++ b/spec/lib/submission_builder/ty2022/states/az/az_return_xml_spec.rb @@ -273,6 +273,18 @@ intake.direct_file_json_data.interest_reports.first&.interest_on_government_bonds = "2.00" expect(xml.css("Subtractions IntUSObligations").text).to eq "2" end + + context "has 1099R subtractions" do + before do + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29a).and_return 500 + allow_any_instance_of(Efile::Az::Az140Calculator).to receive(:calculate_line_29b).and_return 420 + end + + it "should fill out the amount" do + expect(xml.at("Subtractions ExecFedStateLocGovPen").text).to eq "500" + expect(xml.at("Subtractions SubExclBenAnnPen").text).to eq "420" + end + end end end end diff --git a/spec/models/state_file_base_intake_spec.rb b/spec/models/state_file_base_intake_spec.rb index a9d541f870..92de61df01 100644 --- a/spec/models/state_file_base_intake_spec.rb +++ b/spec/models/state_file_base_intake_spec.rb @@ -257,4 +257,60 @@ end end end + + describe "#sum_1099_r_followup_type_for_filer" do + + context "with 1099Rs" do + let!(:intake) { create(:state_file_md_intake, :with_spouse) } + let!(:state_file_1099_r_without_followup) { + create( + :state_file1099_r, + taxable_amount: 1_000, + recipient_ssn: intake.primary.ssn, + intake: intake) + } + let!(:state_file_md1099_r_followup_with_military_service_for_primary_1) do + create( + :state_file_md1099_r_followup, + service_type: "military", + state_file1099_r: create(:state_file1099_r, taxable_amount: 1_000, intake: intake, recipient_ssn: intake.primary.ssn) + ) + end + let!(:state_file_md1099_r_followup_with_military_service_for_primary_2) do + create( + :state_file_md1099_r_followup, + service_type: "military", + state_file1099_r: create(:state_file1099_r, taxable_amount: 1_500, intake: intake, recipient_ssn: intake.primary.ssn) + ) + end + let!(:state_file_md1099_r_followup_with_military_service_for_spouse) do + create( + :state_file_md1099_r_followup, + service_type: "military", + state_file1099_r: create(:state_file1099_r, taxable_amount: 2_000, intake: intake, recipient_ssn: intake.spouse.ssn) + ) + end + let!(:state_file_md1099_r_followup_without_military) do + create( + :state_file_md1099_r_followup, + service_type: "none", + state_file1099_r: create(:state_file1099_r, taxable_amount: 1_000, intake: intake, recipient_ssn: intake.spouse.ssn) + ) + end + + it "totals the followup income" do + expect(intake.sum_1099_r_followup_type_for_filer(:primary, :service_type_military?)).to eq(2_500) + expect(intake.sum_1099_r_followup_type_for_filer(:spouse, :service_type_military?)).to eq(2_000) + end + end + + context "without 1099Rs" do + let(:intake) { create(:state_file_md_intake) } + it "returns 0" do + expect(intake.sum_1099_r_followup_type_for_filer(:primary, :service_type_military?)).to eq(0) + expect(intake.sum_1099_r_followup_type_for_filer(:spouse, :service_type_military?)).to eq(0) + end + end + end + end \ No newline at end of file diff --git a/spec/models/state_file_md_intake_spec.rb b/spec/models/state_file_md_intake_spec.rb index a0f058214c..f1483c03b4 100644 --- a/spec/models/state_file_md_intake_spec.rb +++ b/spec/models/state_file_md_intake_spec.rb @@ -275,61 +275,6 @@ end end - describe "#sum_1099_r_followup_type_for_filer" do - - context "with 1099Rs" do - let!(:intake) { create(:state_file_md_intake, :with_spouse) } - let!(:state_file_1099_r_without_followup) { - create( - :state_file1099_r, - taxable_amount: 1_000, - recipient_ssn: intake.primary.ssn, - intake: intake) - } - let!(:state_file_md1099_r_followup_with_military_service_for_primary_1) do - create( - :state_file_md1099_r_followup, - service_type: "military", - state_file1099_r: create(:state_file1099_r, taxable_amount: 1_000, intake: intake, recipient_ssn: intake.primary.ssn) - ) - end - let!(:state_file_md1099_r_followup_with_military_service_for_primary_2) do - create( - :state_file_md1099_r_followup, - service_type: "military", - state_file1099_r: create(:state_file1099_r, taxable_amount: 1_500, intake: intake, recipient_ssn: intake.primary.ssn) - ) - end - let!(:state_file_md1099_r_followup_with_military_service_for_spouse) do - create( - :state_file_md1099_r_followup, - service_type: "military", - state_file1099_r: create(:state_file1099_r, taxable_amount: 2_000, intake: intake, recipient_ssn: intake.spouse.ssn) - ) - end - let!(:state_file_md1099_r_followup_without_military) do - create( - :state_file_md1099_r_followup, - service_type: "none", - state_file1099_r: create(:state_file1099_r, taxable_amount: 1_000, intake: intake, recipient_ssn: intake.spouse.ssn) - ) - end - - it "totals the followup income" do - expect(intake.sum_1099_r_followup_type_for_filer(:primary, :service_type_military?)).to eq(2_500) - expect(intake.sum_1099_r_followup_type_for_filer(:spouse, :service_type_military?)).to eq(2_000) - end - end - - context "without 1099Rs" do - let(:intake) { create(:state_file_md_intake) } - it "returns 0" do - expect(intake.sum_1099_r_followup_type_for_filer(:primary, :service_type_military?)).to eq(0) - expect(intake.sum_1099_r_followup_type_for_filer(:spouse, :service_type_military?)).to eq(0) - end - end - end - describe "#sum_two_1099_r_followup_types_for_filer" do context "with followups present" do let!(:intake) { create(:state_file_md_intake, :with_spouse) }