From 3003f46b877bfd71a08fc9c478da149d943602f5 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 6 Oct 2026 21:51:59 -0400 Subject: [PATCH 1/3] Keep capital gains and losses out of Massachusetts Part B income ma_part_b_gross_income subtracted Part A and Part C gross income from ma_gross_income. Those net capital losses the Schedule B and D way, but irs_gross_income adds each filer's net capital gain floored at zero, so the difference stayed in Part B: a long-term loss against a short-term gain reduced Part B, and one spouse's short-term loss against the other spouse's long-term gain added phantom Part B income. Subtract the same dividend and capital gain amounts irs_gross_income adds instead (M.G.L. c. 62 s. 2(b), s. 2(d)(1)(M)). Fixes #9953. Co-Authored-By: Claude Opus 5.5 --- changelog.d/ma-part-b-capital-loss.fixed.md | 1 + .../gross_income/ma_part_b_gross_income.yaml | 124 ++++++++++++++++++ .../gross_income/ma_part_b_gross_income.py | 20 ++- 3 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 changelog.d/ma-part-b-capital-loss.fixed.md create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml diff --git a/changelog.d/ma-part-b-capital-loss.fixed.md b/changelog.d/ma-part-b-capital-loss.fixed.md new file mode 100644 index 00000000000..432abc42013 --- /dev/null +++ b/changelog.d/ma-part-b-capital-loss.fixed.md @@ -0,0 +1 @@ +Keep capital gains and losses out of Massachusetts Part B income. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml new file mode 100644 index 00000000000..050ab548a98 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml @@ -0,0 +1,124 @@ +# Capital gains and losses go on Schedules B and D, never on Form 1, +# lines 3 through 10 (Part B). Expected values are computed line by line +# from the 2023 Form 1, Schedule B and Schedule D. A single filer with +# 60,000 of wages and no other 5.0% income has Part B taxable income of +# 60,000 - 2,000 (Form 1, line 11a) - 4,400 (line 18) = 53,600 (line 19). + +- name: A long-term loss applied against short-term gains does not reduce Part B income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_qualified_dividend_income: 1_000 + short_term_capital_gains: 3_000 + long_term_capital_gains: -1_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + # Form 1, line 10 = line 3 = 60,000. + ma_part_b_gross_income: 60_000 + ma_part_b_taxable_income: 53_600 + # Schedule D, line 13 = -1,000; line 14 = Schedule B, line 25 + # = min(1,000, 3,000) = 1,000; line 15 = -1,000 + 1,000 = 0. + # Schedule B: line 26 = 3,000 - 1,000 = 2,000 = line 28; line 31 = 1,000; + # line 32 omitted (Schedule D, line 15 is 0); line 35 = 1,000 + 2,000. + ma_part_a_agi: 3_000 + # Schedule B, line 38 = line 9 = 1,000; line 39 = 3,000 - 1,000 = 2,000. + ma_part_a_taxable_dividend_income: 1_000 + ma_part_a_taxable_capital_gains_income: 2_000 + ma_part_c_agi: 0 + # 5% x (53,600 + 1,000) + 8.5% x 2,000 = 2,730 + 170. + ma_income_tax_before_credits: 2_900 + +- name: A long-term loss applied against short-term gains without dividends + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + short_term_capital_gains: 3_000 + long_term_capital_gains: -1_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule B, line 25 = 1,000; line 28 = line 39 = 2,000. + ma_part_a_agi: 2_000 + ma_part_a_taxable_capital_gains_income: 2_000 + # 5% x 53,600 + 8.5% x 2,000 = 2,680 + 170. + ma_income_tax_before_credits: 2_850 + +- name: A long-term loss larger than the short-term gain does not reduce Part B income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_qualified_dividend_income: 1_000 + short_term_capital_gains: 1_000 + long_term_capital_gains: -3_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + ma_part_b_taxable_income: 53_600 + # Schedule D, line 14 = Schedule B, line 25 = min(3,000, 1,000) = 1,000; + # line 15 = -2,000. Line 32 worksheet: line 2 = min(1,000, 2,000) = 1,000; + # line 4 = 1,000; line 5 = 2,000; line 6 = 1,000. Schedule B, + # line 33 = 1,000 - 1,000 = 0; line 35 = 0 + 0. Schedule D, line 17 + # = -2,000 + 1,000 = -1,000 is carried over (line 23). + ma_part_a_agi: 0 + ma_part_c_agi: 0 + +- name: One spouse's short-term loss against the other spouse's long-term gain does not add to Part B income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + long_term_capital_gains: 5_000 + spouse: + age: 40 + short_term_capital_gains: -2_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + state_code: MA + output: + # Form 1, line 10 = line 3 = 60,000; line 19 = 60,000 - 2,000 - 8,800. + ma_part_b_gross_income: 60_000 + ma_part_b_taxable_income: 49_200 + # Schedule B: line 19c = -2,000; line 20 = 0 (line 9 is 0); line 21 + # = -2,000; line 22 = Schedule D, line 14 = min(2,000, 5,000) = 2,000. + # Schedule D, line 15 = 5,000 - 2,000 = 3,000 = line 21. + ma_part_a_agi: 0 + ma_part_c_agi: 3_000 + # 5% x 49,200 + 5% x 3,000 = 2,460 + 150. + ma_income_tax_before_credits: 2_610 diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py index 24aebb0a591..dca495afe44 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py @@ -11,10 +11,20 @@ class ma_part_b_gross_income(Variable): defined_for = StateCode.MA def formula(tax_unit, period, parameters): + # M.G.L. c. 62 § 2(b)(2): Part B gross income is Massachusetts gross + # income not included in Part A or Part C gross income. ma_gross_income = tax_unit("ma_gross_income", period) - ma_part_a_gross_income = tax_unit("ma_part_a_gross_income", period) - ma_part_c_gross_income = tax_unit("ma_part_c_gross_income", period) - return max_( - 0, - ma_gross_income - ma_part_a_gross_income - ma_part_c_gross_income, + # ma_gross_income starts from irs_gross_income, which adds each + # filer's dividends and net capital gain floored at zero. Remove those + # same amounts: they go on Schedules B and D, and capital losses never + # reduce Part B income (§ 2(d)(1)(M) disallows IRC § 62(a)(3)). + # Subtracting Part A and Part C gross income instead would leave the + # difference between their loss netting and irs_gross_income's in Part B. + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + dividends = max_(0, person("dividend_income", period)) + capital_gains = max_(0, person("capital_gains", period)) + part_a_and_c_income = tax_unit.sum( + where(is_dependent, 0, dividends + capital_gains) ) + return max_(0, ma_gross_income - part_a_and_c_income) From 01b18738973aff7543073f78f2413f677f363db9 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 6 Oct 2026 22:06:21 -0400 Subject: [PATCH 2/3] Count capital gain distributions on Massachusetts Schedule D non_sch_d_capital_gains (Form 1040 line 7 distributions without a federal Schedule D) entered ma_gross_income through irs_gross_income but neither Part A nor Part C, so it stayed in Part B. Massachusetts reports them on Schedule D, line 6: add them to the long-term amount in ma_part_c_gross_income and ma_part_a_agi, and take them out of ma_part_b_gross_income. Fixes #9957. Co-Authored-By: Claude Opus 5.5 --- changelog.d/ma-part-b-capital-loss.fixed.md | 2 +- .../gross_income/ma_part_b_gross_income.yaml | 104 ++++++++++++++++++ .../adjusted_gross_income/ma_part_a_agi.py | 6 +- .../gross_income/ma_part_b_gross_income.py | 5 +- .../gross_income/ma_part_c_gross_income.py | 7 +- 5 files changed, 119 insertions(+), 5 deletions(-) diff --git a/changelog.d/ma-part-b-capital-loss.fixed.md b/changelog.d/ma-part-b-capital-loss.fixed.md index 432abc42013..24904f8d490 100644 --- a/changelog.d/ma-part-b-capital-loss.fixed.md +++ b/changelog.d/ma-part-b-capital-loss.fixed.md @@ -1 +1 @@ -Keep capital gains and losses out of Massachusetts Part B income. +Keep capital gains and losses out of Massachusetts Part B income, and count capital gain distributions reported without a federal Schedule D on Massachusetts Schedule D (Part C). diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml index 050ab548a98..007a22c4a0f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.yaml @@ -122,3 +122,107 @@ ma_part_c_agi: 3_000 # 5% x 49,200 + 5% x 3,000 = 2,460 + 150. ma_income_tax_before_credits: 2_610 + +- name: Capital gain distributions without a federal Schedule D are Part C income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_sch_d_capital_gains: 5_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + ma_part_b_taxable_income: 53_600 + # Schedule D, line 6 = 5,000 = lines 9, 11, 13, 15, 17, 19 and 21. + ma_part_c_gross_income: 5_000 + ma_part_c_agi: 5_000 + # 5% x 53,600 + 5% x 5,000 = 2,680 + 250. + ma_income_tax_before_credits: 2_930 + +- name: A short-term loss offsets capital gain distributions in Part C + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_sch_d_capital_gains: 5_000 + short_term_capital_gains: -2_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule B: line 19c = -2,000; line 20 = 0 (line 9 is 0); line 21 + # = -2,000; line 22 = Schedule D, line 14 = min(2,000, 5,000) = 2,000. + # Schedule D, line 15 = 5,000 - 2,000 = 3,000. + ma_part_c_agi: 3_000 + # 5% x 53,600 + 5% x 3,000 = 2,680 + 150. + ma_income_tax_before_credits: 2_830 + +- name: A long-term loss offsets capital gain distributions on Schedule D + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_sch_d_capital_gains: 5_000 + long_term_capital_gains: -3_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule D: line 1 = -3,000; line 6 = 5,000; line 9 = 2,000 = line 13 + # = line 15 = line 21. + ma_part_c_agi: 2_000 + # 5% x 53,600 + 5% x 2,000 = 2,680 + 100. + ma_income_tax_before_credits: 2_780 + +- name: Capital gain distributions that cover a long-term loss leave short-term gains whole + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_sch_d_capital_gains: 5_000 + short_term_capital_gains: 3_000 + long_term_capital_gains: -1_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule D, line 13 = -1,000 + 5,000 = 4,000, so Schedule B, line 25 + # is omitted: line 26 = line 24 = 3,000 = line 28 = line 39. + ma_part_a_agi: 3_000 + ma_part_a_taxable_capital_gains_income: 3_000 + ma_part_c_agi: 4_000 + # 5% x 53,600 + 8.5% x 3,000 + 5% x 4,000 = 2,680 + 255 + 200. + ma_income_tax_before_credits: 3_135 diff --git a/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py b/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py index 2120a051cec..cad995449ef 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py @@ -30,7 +30,11 @@ def formula(tax_unit, period, parameters): short_term_capital_loss, ), ) - long_term_capital_gains = add(tax_unit, period, ["long_term_capital_gains"]) + # Massachusetts Schedule D, line 13 includes capital gain + # distributions reported without a federal Schedule D (line 6). + long_term_capital_gains = add( + tax_unit, period, ["long_term_capital_gains", "non_sch_d_capital_gains"] + ) long_term_capital_loss = max_(0, -long_term_capital_gains) long_term_loss_against_short_term_gain = min_( diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py index dca495afe44..302668b8391 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py @@ -24,7 +24,10 @@ def formula(tax_unit, period, parameters): is_dependent = person("is_tax_unit_dependent", period) dividends = max_(0, person("dividend_income", period)) capital_gains = max_(0, person("capital_gains", period)) + # Capital gain distributions reported without a federal Schedule D + # go on Massachusetts Schedule D, line 6. + distributions = max_(0, person("non_sch_d_capital_gains", period)) part_a_and_c_income = tax_unit.sum( - where(is_dependent, 0, dividends + capital_gains) + where(is_dependent, 0, dividends + capital_gains + distributions) ) return max_(0, ma_gross_income - part_a_and_c_income) diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py index 9536895d297..cb800ca68d1 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py @@ -11,8 +11,11 @@ class ma_part_c_gross_income(Variable): defined_for = StateCode.MA def formula(tax_unit, period, parameters): - # Long-term capital gains - ltcg = add(tax_unit, period, ["long_term_capital_gains"]) + # Long-term capital gains, with capital gain distributions reported + # without a federal Schedule D (Massachusetts Schedule D, line 6) + ltcg = add( + tax_unit, period, ["long_term_capital_gains", "non_sch_d_capital_gains"] + ) # Short-term capital gains (can be negative) stcg = add(tax_unit, period, ["short_term_capital_gains"]) # Per MA Schedule B line 22, short-term losses offset long-term gains From dfd20a593e79888d427dab7b945cb4b47baf421a Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 7 Oct 2026 10:49:07 -0400 Subject: [PATCH 3/3] Count Form 4797 gains and losses on Massachusetts Schedule D other_net_gain (Form 4797 line 18b, Schedule 1 line 4) entered ma_gross_income only through irs_gross_income, so a gain stayed in Part B and a loss was dropped. Massachusetts reports Form 4797, Part II amounts on Schedule D, line 7. Add ma_long_term_capital_gains for the long-term Schedule D amount (long-term gains, line 6 distributions and line 7 Form 4797 amounts), use it in ma_part_c_gross_income and ma_part_a_agi, and take other_net_gain_gross_income out of ma_part_b_gross_income. Also renames part_a_and_c_income to filer_dividends_and_gains and cites the Schedule D instructions in the Part B and Part C references, from the #9954 review. Fixes #9990. Co-Authored-By: Claude Opus 5.5 --- changelog.d/ma-form-4797-schedule-d.fixed.md | 1 + .../ma_long_term_capital_gains.yaml | 158 ++++++++++++++++++ .../adjusted_gross_income/ma_part_a_agi.py | 7 +- .../ma_long_term_capital_gains.py | 27 +++ .../gross_income/ma_part_b_gross_income.py | 20 ++- .../gross_income/ma_part_c_gross_income.py | 12 +- 6 files changed, 209 insertions(+), 16 deletions(-) create mode 100644 changelog.d/ma-form-4797-schedule-d.fixed.md create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.yaml create mode 100644 policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.py diff --git a/changelog.d/ma-form-4797-schedule-d.fixed.md b/changelog.d/ma-form-4797-schedule-d.fixed.md new file mode 100644 index 00000000000..eb2980bcf16 --- /dev/null +++ b/changelog.d/ma-form-4797-schedule-d.fixed.md @@ -0,0 +1 @@ +Count Form 4797 gains and losses on Massachusetts Schedule D (Part C) instead of Part B. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.yaml new file mode 100644 index 00000000000..6786cf1e7df --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.yaml @@ -0,0 +1,158 @@ +# Form 4797, Part II gains and losses (other_net_gain) go on Massachusetts +# Schedule D, line 7, not on Form 1, lines 3 through 10 (Part B). Expected +# values are computed line by line from the 2023 Form 1, Schedule B and +# Schedule D. A single filer with 60,000 of wages and no other 5.0% income +# has Part B taxable income of 60,000 - 2,000 (Form 1, line 11a) - 4,400 +# (line 18) = 53,600 (line 19), taxed at 5% = 2,680. + +- name: Long-term amounts on Schedule D add long-term gains, distributions and Form 4797 amounts + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + long_term_capital_gains: 4_000 + non_sch_d_capital_gains: 1_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: -2_000 + households: + household: + members: [head] + state_code: MA + output: + # Schedule D: line 1 = 4,000; line 6 = 1,000; line 7 = -2,000. + ma_long_term_capital_gains: 3_000 + +- name: A Form 4797 gain is Part C income + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: 5_000 + households: + household: + members: [head] + state_code: MA + output: + # Form 1, line 10 = line 3 = 60,000. + ma_part_b_gross_income: 60_000 + # Schedule D, line 7 = 5,000 = lines 9, 13, 15, 17, 19 and 21. + ma_part_c_gross_income: 5_000 + ma_part_c_agi: 5_000 + # 2,680 + 5% x 5,000. + ma_income_tax_before_credits: 2_930 + +- name: A short-term loss offsets a Form 4797 gain in Part C + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + short_term_capital_gains: -2_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: 5_000 + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule B: line 19c = -2,000; line 20 = 0 (line 9 is 0); line 21 + # = -2,000; line 22 = Schedule D, line 14 = min(2,000, 5,000) = 2,000. + # Schedule D, line 15 = 5,000 - 2,000 = 3,000. + ma_part_c_agi: 3_000 + # 2,680 + 5% x 3,000. + ma_income_tax_before_credits: 2_830 + +- name: A Form 4797 loss offsets long-term gains on Schedule D + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + long_term_capital_gains: 5_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: -3_000 + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule D: line 1 = 5,000; line 7 = -3,000; line 9 = 2,000 = line 13 + # = line 15 = line 21. + ma_part_c_agi: 2_000 + # 2,680 + 5% x 2,000. + ma_income_tax_before_credits: 2_780 + +- name: A Form 4797 loss offsets short-term gains on Schedule B, line 25 + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + short_term_capital_gains: 3_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: -1_000 + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule D, line 13 = line 7 = -1,000; line 14 = Schedule B, line 25 + # = min(1,000, 3,000) = 1,000; line 15 = 0. Schedule B, line 26 + # = 3,000 - 1,000 = 2,000 = line 28 = line 39. + ma_part_a_agi: 2_000 + ma_part_a_taxable_capital_gains_income: 2_000 + ma_part_c_agi: 0 + # 2,680 + 8.5% x 2,000. + ma_income_tax_before_credits: 2_850 + +- name: A Form 4797 loss applies against dividends on Schedule B, line 32 + period: 2023 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + employment_income: 60_000 + non_qualified_dividend_income: 1_000 + tax_units: + tax_unit: + members: [head] + other_net_gain: -3_000 + households: + household: + members: [head] + state_code: MA + output: + ma_part_b_gross_income: 60_000 + # Schedule D, line 13 = -3,000; Schedule B, line 24 = 0, so line 14 = 0 + # and line 15 = -3,000. Line 32 worksheet: line 2 = min(1,000, 2,000) + # = 1,000; line 4 = 1,000; line 5 = 3,000; line 6 = 1,000. Schedule B, + # line 33 = 1,000 - 1,000 = 0 = line 35. Schedule D, line 17 = -3,000 + # + 1,000 = -2,000 is carried over (line 23). + ma_part_a_agi: 0 + ma_part_c_agi: 0 diff --git a/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py b/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py index cad995449ef..937b4c0d19f 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_a_agi.py @@ -30,11 +30,8 @@ def formula(tax_unit, period, parameters): short_term_capital_loss, ), ) - # Massachusetts Schedule D, line 13 includes capital gain - # distributions reported without a federal Schedule D (line 6). - long_term_capital_gains = add( - tax_unit, period, ["long_term_capital_gains", "non_sch_d_capital_gains"] - ) + # Long-term amounts on Massachusetts Schedule D (line 13). + long_term_capital_gains = tax_unit("ma_long_term_capital_gains", period) long_term_capital_loss = max_(0, -long_term_capital_gains) long_term_loss_against_short_term_gain = min_( diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.py new file mode 100644 index 00000000000..adeb46c1a39 --- /dev/null +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_long_term_capital_gains.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ma_long_term_capital_gains(Variable): + value_type = float + entity = TaxUnit + label = "MA long-term capital gains and losses" + documentation = ( + "Long-term amounts on Massachusetts Schedule D: long-term capital " + "gains and losses, capital gain distributions reported without a " + "federal Schedule D (line 6) and Form 4797, Part II gains and losses " + "(line 7). PolicyEngine has a single Form 4797 input, so it also " + "counts any gain or loss on business property held one year or less, " + "which belongs on Schedule B, lines 12 and 17." + ) + unit = USD + definition_period = YEAR + reference = ( + "https://taxsim.nber.org/historical_state_tax_forms/MA/2023/dor-2023-inc-sch-d-(form-1).pdf", + "https://taxsim.nber.org/historical_state_tax_forms/MA/2023/dor-2023-inc-form1-instructions.pdf#page=27", + ) + defined_for = StateCode.MA + adds = [ + "long_term_capital_gains", + "non_sch_d_capital_gains", + "other_net_gain", + ] diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py index 302668b8391..7d2646795a7 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_b_gross_income.py @@ -7,7 +7,10 @@ class ma_part_b_gross_income(Variable): label = "MA Part B gross income" unit = USD definition_period = YEAR - reference = "https://www.mass.gov/info-details/mass-general-laws-c62-ss-2" + reference = ( + "https://www.mass.gov/info-details/mass-general-laws-c62-ss-2", + "https://taxsim.nber.org/historical_state_tax_forms/MA/2023/dor-2023-inc-form1-instructions.pdf#page=27", + ) defined_for = StateCode.MA def formula(tax_unit, period, parameters): @@ -25,9 +28,16 @@ def formula(tax_unit, period, parameters): dividends = max_(0, person("dividend_income", period)) capital_gains = max_(0, person("capital_gains", period)) # Capital gain distributions reported without a federal Schedule D - # go on Massachusetts Schedule D, line 6. + # go on Massachusetts Schedule D, line 6, and Form 4797, Part II + # gains on line 7. other_net_gain_gross_income is already the + # filers' positive share. distributions = max_(0, person("non_sch_d_capital_gains", period)) - part_a_and_c_income = tax_unit.sum( - where(is_dependent, 0, dividends + capital_gains + distributions) + form_4797_gains = person("other_net_gain_gross_income", period) + filer_dividends_and_gains = tax_unit.sum( + where( + is_dependent, + 0, + dividends + capital_gains + distributions + form_4797_gains, + ) ) - return max_(0, ma_gross_income - part_a_and_c_income) + return max_(0, ma_gross_income - filer_dividends_and_gains) diff --git a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py index cb800ca68d1..ae5d11d83bf 100644 --- a/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py +++ b/policyengine_us/variables/gov/states/ma/tax/income/gross_income/ma_part_c_gross_income.py @@ -7,15 +7,15 @@ class ma_part_c_gross_income(Variable): label = "MA Part C gross income" unit = USD definition_period = YEAR - reference = "https://www.mass.gov/info-details/mass-general-laws-c62-ss-2" # (b)(3) + reference = ( + "https://www.mass.gov/info-details/mass-general-laws-c62-ss-2", # (b)(3) + "https://taxsim.nber.org/historical_state_tax_forms/MA/2023/dor-2023-inc-form1-instructions.pdf#page=27", + ) defined_for = StateCode.MA def formula(tax_unit, period, parameters): - # Long-term capital gains, with capital gain distributions reported - # without a federal Schedule D (Massachusetts Schedule D, line 6) - ltcg = add( - tax_unit, period, ["long_term_capital_gains", "non_sch_d_capital_gains"] - ) + # Long-term amounts on Massachusetts Schedule D + ltcg = tax_unit("ma_long_term_capital_gains", period) # Short-term capital gains (can be negative) stcg = add(tax_unit, period, ["short_term_capital_gains"]) # Per MA Schedule B line 22, short-term losses offset long-term gains