Business-Tax-US-Form_1040-Worksheets
view release on metacpan or search on metacpan
lib/Business/Tax/US/Form_1040/Worksheets.pm view on Meta::CPAN
$inputs = {
box5 => 30000.00, # Sum of box 5 on all Forms SSA-1099 and RRB-1099
l1z => 0, # Form 1040, line 1z
l2b => 350.00,
l3b => 6000.00,
l4b => 0,
l5b => 8000.00,
l7a => 1600.00, # Use 'l7' for tax years 2022 through 2024
l8 => 1000.00,
l2a => 0,
s1l11 => 0, # Schedule 1 (Form 1040), line 11
s1l12 => 0,
s1l13 => 0,
s1l14 => 0,
s1l15 => 0,
s1l16 => 0,
s1l17 => 0,
s1l18 => 0,
s1l19 => 0,
s1l20 => 0,
s1l23 => 0,
s1l25 => 0,
status => 'single', # Social Security Benefits Worksheet, line 8
filing_year => 2025,
};
Appropriate values for elements in C<$inputs>:
=over 4
=item * C<l7a>: Capital gain (or loss): Number holding dollar amount (to
2-decimal maximum). If value is C<0>, element may be omitted.
B<NOTE: For tax years up through 2024, use the value on Line 7 of IRS Form
1040. Beginning with tax year 2025, this value is entered on Line 7a of IRS
Form 1040.>
=item * C<status>: String holding one of C<married single married_sep>.
=item * C<filing_year>: Filing year (4-digits).
=item *
All others: Number holding dollar amount (to 2-decimal maximum). If value is
C<0>, element may be omitted.
=back
=item * Return Value
Scalar holding taxable social security benefits in dollars and two cents,
I<e.g.,> C<289.73>.
=back
=cut
my %data_2022_ssb = (
worksheet_line_count => 18,
ssa_percentage => 0.5,
percentage_a => 0.85,
percentage_b => 0.85,
percentage_c => 0.85,
married_amt_a => 32000,
single_amt_a => 25000,
married_amt_b => 12000,
single_amt_b => 9000,
other_percentage => 0.5,
);
# inspection of 2023 Soc Sec worksheet indicates no change in
# parameters
my %data_2023_ssb = map { $_ => $data_2022_ssb{$_} } keys %data_2022_ssb;
# inspection of 2024 Soc Sec worksheet indicates no change in
# parameters
my %data_2024_ssb = map { $_ => $data_2023_ssb{$_} } keys %data_2023_ssb;
# inspection of 2025 Soc Sec worksheet indicates no change in
# parameters
my %data_2025_ssb = map { $_ => $data_2024_ssb{$_} } keys %data_2024_ssb;
our %params = (
ssb => {
2022 => { %data_2022_ssb },
2023 => { %data_2023_ssb },
2024 => { %data_2024_ssb },
2025 => { %data_2025_ssb },
},
qd => {
2022 => {
worksheet_line_count => 21,
single_or_married_sep_amt_a => 41675,
married_amt_a => 83350,
head_of_household_amt_a => 55800,
single_amt_b => 459750,
married_sep_amt_b => 258600,
married_amt_b => 517200,
head_of_household_amt_b => 488500,
percentage_a => 0.15,
percentage_b => 0.20,
},
2023 => {
worksheet_line_count => 21,
single_or_married_sep_amt_a => 44625,
married_amt_a => 89250,
head_of_household_amt_a => 59750,
single_amt_b => 492300,
married_sep_amt_b => 276900,
married_amt_b => 553850,
head_of_household_amt_b => 523050,
percentage_a => 0.15,
percentage_b => 0.20,
},
2024 => {
worksheet_line_count => 21,
single_or_married_sep_amt_a => 47025,
married_amt_a => 94050,
head_of_household_amt_a => 63000,
single_amt_b => 518900,
married_sep_amt_b => 291850,
married_amt_b => 583750,
head_of_household_amt_b => 551350,
percentage_a => 0.15,
percentage_b => 0.20,
},
2025 => {
worksheet_line_count => 21,
single_or_married_sep_amt_a => 48350,
married_amt_a => 96700,
head_of_household_amt_a => 64750,
single_amt_b => 533400,
married_sep_amt_b => 300000,
married_amt_b => 600050,
head_of_household_amt_b => 566700,
percentage_a => 0.15,
percentage_b => 0.20,
},
},
);
sub social_security_benefits {
my ($inputs) = @_;
my $rv = _social_security_benefits_engine($inputs);
return $rv->{taxable_benefits};
}
=head2 C<social_security_worksheet_data()>
=over 4
=item * Purpose
Calculate data needed for the purpose of completing all entries (except
checkboxes) on the Social Security Benefits Worksheet.
my $worksheet_data = social_security_worksheet_data( $inputs );
=item * Arguments
The same, single hash reference which is supplied to
C<social_security_benefits()> (I<q.v.> above).
=item * Return Value
Reference to an array holding the data to be entered on lines 1-18 of the SSBW.
The indexes to the elements of that array correspond to those line numbers on the SSBW.
=back
=cut
sub social_security_worksheet_data {
my ($inputs) = @_;
my $rv = _social_security_benefits_engine($inputs);
return $rv->{worksheet_data};
}
sub _social_security_benefits_engine {
my ($inputs) = @_;
croak "Argument to social_security_benefits() must be hashref"
unless ref($inputs) eq 'HASH';
croak "Must include 4-digit value for 'filing_year' in argument to social_security_benefits()"
unless $inputs->{filing_year};
my $filing_year = $inputs->{filing_year}; # TODO add test for numeric; required element
croak "Must include 4-digit value for 'filing_year' in argument to social_security_benefits()"
unless $inputs->{filing_year} =~ m/^\d{4}$/;
croak "'filing_year' must be > 2000" unless $inputs->{filing_year} > 2000;
my @numerics = (
qw(
box5
l1z
l2b
l3b
l4b
l5b
),
$filing_year <= 2024 ? 'l7' : 'l7a',
qw(
l8
l2a
s1l11 s1l12 s1l13 s1l14 s1l15
s1l16 s1l17 s1l18 s1l19 s1l20
s1l23
s1l25
),
);
my %permitted = map { $_ => 1 } (@numerics, 'status', 'filing_year');
for my $k (keys %{$inputs}) {
croak "Invalid element in hashref passed to social_security_benefits()"
unless $permitted{$k};
}
my %permitted_statuses = map { $_ => 1 } ( qw|
married single married_sep
| );
croak "Invalid value for 'status' element"
unless (defined $inputs->{status} and $permitted_statuses{$inputs->{status}});
my $data = {};
for my $el (@numerics) {
$data->{$el} = $inputs->{$el} // 0;
}
$data->{status} = $inputs->{status};
my @lines = (undef, (undef) x $params{ssb}{$filing_year}{worksheet_line_count});
my $formatted_lines;
$lines[1] = $data->{box5};
$lines[2] = $lines[1] * $params{ssb}{$filing_year}{ssa_percentage};
$lines[3] =
$data->{l1z} +
$data->{l2b} +
$data->{l3b} +
$data->{l4b} +
$data->{l5b} +
($filing_year <= 2024 ? $data->{l7} : $data->{l7a}) +
$data->{l8};
$lines[4] = $data->{l2a};
$lines[5] = $lines[2] + $lines[3] + $lines[4];
# sum up some Adjustments to Income (Schedule 1, Part II)
$lines[6] =
$data->{s1l11} +
$data->{s1l12} +
$data->{s1l13} +
$data->{s1l14} +
$data->{s1l15} +
$data->{s1l16} +
$data->{s1l17} +
$data->{s1l18} +
$data->{s1l19} +
$data->{s1l20} +
$data->{s1l23} +
$data->{s1l25};
if (! ($lines[6] < $lines[5]) ) {
$formatted_lines = decimal_lines(\@lines);
return {
taxable_benefits => 0,
worksheet_data => $formatted_lines,
};
}
$lines[7] = $lines[5] - $lines[6];
if ($data->{status} eq 'married_sep') {
$lines[16] = $lines[7] * $params{ssb}{$filing_year}{percentage_b};
$lines[17] = $lines[1] * $params{ssb}{$filing_year}{percentage_c};
$lines[18] = min($lines[16], $lines[17]);
$formatted_lines = decimal_lines(\@lines);
return {
taxable_benefits => $lines[18],
worksheet_data => $formatted_lines,
};
}
$lines[8] = $data->{status} eq 'married'
? $params{ssb}{$filing_year}{married_amt_a}
: $params{ssb}{$filing_year}{single_amt_a};
unless ($lines[8] < $lines[7]) {
$formatted_lines = decimal_lines(\@lines);
return {
taxable_benefits => 0,
worksheet_data => $formatted_lines,
};
}
$lines[9] = $lines[7] - $lines[8];
$lines[10] = $data->{status} eq 'married'
? $params{ssb}{$filing_year}{married_amt_b}
: $params{ssb}{$filing_year}{single_amt_b};
my $diff = $lines[9] - $lines[10];
$lines[11] = $diff > 0 ? $diff : 0;
$lines[12] = min($lines[9], $lines[10]);
$lines[13] = $lines[12] * $params{ssb}{$filing_year}{other_percentage};
$lines[14] = min($lines[2], $lines[13]);
my $x = $lines[11] * $params{ssb}{$filing_year}{percentage_a};
$lines[15] = $x > 0 ? $x : 0;
$lines[16] = $lines[14] + $lines[15];
$lines[17] = $lines[1] * $params{ssb}{$filing_year}{percentage_c};
$lines[18] = min($lines[16], $lines[17]);
$formatted_lines = decimal_lines(\@lines);
return {
taxable_benefits => $lines[18],
worksheet_data => $formatted_lines,
};
}
=head2 C<pp_ssbw()>
=over 4
=item * Purpose
Pretty-print ('pp' for short) the results of
C<social_security_worksheet_data()> for easier transcription to printed
worksheet.
pp_ssbw($results);
=item * Arguments
The array reference which is the return value of
C<social_security_worksheet_data()>. Required.
=item * Return Value
Implicitly returns true value upon success.
=item * Comment
In a future version of this library, this function may take a second argument
which presumably will be a string holding the path to an output file. For
now, the function simply prints to C<STDOUT>.
=back
=cut
sub _compose_worksheet_line {
my ($line_number, $formatting, $text, $result) = @_;
my $line = sprintf("$formatting" => (
$line_number,
$text,
$line_number,
$result,
) );
return $line;
}
sub pp_ssbw {
my ($results) = @_;
croak "First argument to pp_ssbw() must be array reference"
unless ref($results) eq 'ARRAY';
my @output = ();
my $line_number = 0;
my $one_wide_format = "% 2s. %-40s % 2s. % 12.2f";
my $two_wide_format = "% 2s. %-52s % 2s. % 12.2f";
my @f = (undef, $one_wide_format, $two_wide_format);
lib/Business/Tax/US/Form_1040/Worksheets.pm view on Meta::CPAN
head_of_household
| );
croak "Invalid value for 'status1' element"
unless (defined $inputs->{status1} and $permitted_statuses_1{$inputs->{status1}});
my %permitted_statuses_2 = map { $_ => 1 } ( qw|
single
married_sep
married
head_of_household
| );
croak "Invalid value for 'status2' element"
unless (defined $inputs->{status2} and $permitted_statuses_2{$inputs->{status2}});
my %permitted = map { $_ => 1 } (@numerics, 'status1', 'status2', 'filing_year');
for my $k (keys %{$inputs}) {
croak "Invalid element in hashref passed to qualified_dividends_capital_gains_tax()"
unless $permitted{$k};
}
my $data = {};
for my $el (@numerics) {
$inputs->{$el} //= 0;
$data->{$el} = $inputs->{$el};
}
$data->{status1} = $inputs->{status1};
$data->{status2} = $inputs->{status2};
my $filing_year = $inputs->{filing_year}; # TODO add test for numeric; required element
my @lines = (undef, (undef) x $params{qd}{$filing_year}{worksheet_line_count});
# We will return after line 21 because thereafter we have to look up
# things in the Tax Table.
$lines[1] = $inputs->{l15};
$lines[2] = $inputs->{l3a};
$lines[3] = $inputs->{sD};
$lines[4] = $lines[2] + $lines[3];
my $diff = $lines[1] - $lines[4];
$lines[5] = $diff > 0 ? $diff : 0;
$lines[6] = $inputs->{status1} eq 'single_or_married_sep'
? $params{qd}{$filing_year}{single_or_married_sep_amt_a}
: $inputs->{status1} eq 'married'
? $params{qd}{$filing_year}{married_amt_a}
: $params{qd}{$filing_year}{head_of_household_amt_a};
$lines[7] = min($lines[1], $lines[6]);
$lines[8] = min($lines[5], $lines[7]);
$lines[9] = $lines[7] - $lines[8];
$lines[10] = min($lines[1], $lines[4]);
$lines[11] = $lines[9];
$lines[12] = $lines[10] - $lines[11];
$lines[13] = $inputs->{status2} eq 'single'
? $params{qd}{$filing_year}{single_amt_b}
: $inputs->{status2} eq 'married_sep'
? $params{qd}{$filing_year}{married_sep_amt_b}
: $inputs->{status2} eq 'married'
? $params{qd}{$filing_year}{married_amt_b}
: $params{qd}{$filing_year}{head_of_household_amt_b};
$lines[14] = min($lines[1], $lines[13]);
$lines[15] = $lines[5] + $lines[9];
my $diff1 = $lines[14] - $lines[15];
$lines[16] = $diff1 > 0 ? $diff1 : 0;
$lines[17] = min($lines[12], $lines[16]);
$lines[18] = $lines[17] * $params{qd}{$filing_year}{percentage_a};
$lines[19] = $lines[9] + $lines[17];
$lines[20] = $lines[10] - $lines[19];
$lines[21] = $lines[20] * $params{qd}{$filing_year}{percentage_b};
# We will need to use 5, 18, 21, 22 and 1
my @formatted_lines = (
$lines[0], # undef
map { sprintf("%.2f" => $lines[$_]) } (1..$#lines),
);
return \@formatted_lines;
}
=head2 C<pp_qdcgtw()>
=over 4
=item * Purpose
Pretty-print ('pp' for short) the results of
C<qualified_dividends_capital_gains_tax()> for easier transcription to printed
worksheet.
pp_qdcgtw($results);
=item * Arguments
The array reference which is the return value of
C<qualified_dividends_capital_gains_tax()>. Required.
=item * Return Value
Implicitly returns true value upon success.
=item * Comment
In a future version of this library, this function may take a second argument
which presumably will be a string holding the path to an output file. For
now, the function simply prints to C<STDOUT>.
=back
=cut
sub pp_qdcgtw {
my ($results) = @_;
croak "First argument to pp_qdcgtw() must be array reference"
unless ref($results) eq 'ARRAY';
my @output = ();
my $line_number = 0;
my $one_wide_format = "% 2s. %-28s % 2s. % 12.2f";
my $two_wide_format = "% 2s. %-40s % 2s. % 12.2f";
my $three_wide_format = "% 2s. %-52s % 2s. % 12.2f";
my @f = (undef, $one_wide_format, $two_wide_format, $three_wide_format);
my $lines = [
undef,
{ formatting => $f[2], text => "Enter Form 1040, line 15" },
{ formatting => $f[1], text => "Enter Form 1040, line 3a" },
{ formatting => $f[1], text => "Sche. D/Form 1040, line 7/7a" },
{ formatting => $f[1], text => "Line 2 - Line 3" },
{ formatting => $f[2], text => "Line 1 - Line 4" },
{ formatting => $f[2], text => "Filing status amount (1)" },
{ formatting => $f[2], text => "Smaller of lines 1 or 6" },
{ formatting => $f[2], text => "Smaller of lines 5 or 7" },
( run in 1.035 second using v1.01-cache-2.11-cpan-364913b4093 )