File Coverage

blib/lib/Business/Tax/US/Form_1040/Worksheets.pm
Criterion Covered Total %
statement 167 167 100.0
branch 58 58 100.0
condition 16 16 100.0
subroutine 14 14 100.0
pod 6 6 100.0
total 261 261 100.0


line stmt bran cond sub pod time code
1             package Business::Tax::US::Form_1040::Worksheets;
2 10     10   1182205 use 5.14.0;
  10         42  
3 10     10   54 use warnings;
  10         21  
  10         709  
4 10     10   102 use Carp;
  10         44  
  10         1131  
5             #use Data::Dump qw(dd pp);
6              
7             BEGIN {
8 10     10   92 use Exporter ();
  10         38  
  10         317  
9 10     10   58 use List::Util qw( min );
  10         21  
  10         1626  
10 10     10   33 our ($VERSION, @ISA, @EXPORT_OK);
11 10         45 $VERSION = '0.08';
12 10         156 @ISA = qw(Exporter);
13 10         33434 @EXPORT_OK = qw(
14             social_security_benefits
15             social_security_worksheet_data
16             pp_ssbw
17             qualified_dividends_capital_gains_tax
18             pp_qdcgtw
19             decimal_lines
20             );
21             }
22              
23             =head1 NAME
24              
25             Business::Tax::US::Form_1040::Worksheets - IRS Form 1040 worksheets calculations
26              
27             =head1 SYNOPSIS
28              
29             use Business::Tax::US::Form_1040::Worksheets qw(
30             social_security_benefits
31             social_security_worksheet_data
32             qualified_dividends_capital_gains_tax
33             pp_qdcgtw
34             decimal_lines
35             );
36              
37             $benefits = social_security_benefits( $inputs );
38              
39             $worksheet_data = social_security_worksheet_data( $inputs );
40              
41             $lines = qualified_dividends_capital_gains_tax( $inputs );
42              
43             pp_qdcgtw($lines);
44              
45             =head1 DESCRIPTION
46              
47             This library exports, on demand only, functions which implement calculations
48             used in various worksheets found in U.S. IRS Form 1040 instructions.
49              
50             B
51              
52             =over 4
53              
54             =item *
55              
56             B I, I as found on page 32
57             of IRS Form 1040 Instructions for filing year 2025.
58              
59             =item *
60              
61             B I, I as
62             found on page 38 of those 2025 Instructions.
63              
64             =back
65              
66             The current version of this library supports the SSBW and most of the QDCGTW
67             for filing years 2022, 2023, 2024 and 2025. Future versions may extend the
68             support of those worksheets forwards and backwords; may offer more complete
69             support for the QDCGTW; and may offer support for other worksheets found
70             within the Form 1040 instructions.
71              
72             B
73             the Internal Revenue Service, any other tax authority, accountant or attorney.
74             Use at your own risk!>
75              
76             =head1 SUBROUTINES
77              
78             =head2 C
79              
80             =over 4
81              
82             =item * Purpose
83              
84             Calculate taxable social security benefits per the SSBW for the purpose of
85             entering the amount of such taxable benefits on IRS Form 1040. (For filing
86             year 2025, these would be lines 6a and 6b on that form.)
87              
88             my $benefits = social_security_benefits( $inputs );
89              
90             =item * Arguments
91              
92             Single hash reference with the following keys (values displayed here are
93             purely for example):
94              
95             $inputs = {
96             box5 => 30000.00, # Sum of box 5 on all Forms SSA-1099 and RRB-1099
97             l1z => 0, # Form 1040, line 1z
98             l2b => 350.00,
99             l3b => 6000.00,
100             l4b => 0,
101             l5b => 8000.00,
102             l7a => 1600.00, # Use 'l7' for tax years 2022 through 2024
103             l8 => 1000.00,
104             l2a => 0,
105             s1l11 => 0, # Schedule 1 (Form 1040), line 11
106             s1l12 => 0,
107             s1l13 => 0,
108             s1l14 => 0,
109             s1l15 => 0,
110             s1l16 => 0,
111             s1l17 => 0,
112             s1l18 => 0,
113             s1l19 => 0,
114             s1l20 => 0,
115             s1l23 => 0,
116             s1l25 => 0,
117             status => 'single', # Social Security Benefits Worksheet, line 8
118             filing_year => 2025,
119             };
120              
121             Appropriate values for elements in C<$inputs>:
122              
123             =over 4
124              
125             =item * C: Capital gain (or loss): Number holding dollar amount (to
126             2-decimal maximum). If value is C<0>, element may be omitted.
127              
128             B
129             1040. Beginning with tax year 2025, this value is entered on Line 7a of IRS
130             Form 1040.>
131              
132             =item * C: String holding one of C.
133              
134             =item * C: Filing year (4-digits).
135              
136             =item *
137              
138             All others: Number holding dollar amount (to 2-decimal maximum). If value is
139             C<0>, element may be omitted.
140              
141             =back
142              
143             =item * Return Value
144              
145             Scalar holding taxable social security benefits in dollars and two cents,
146             I C<289.73>.
147              
148             =back
149              
150             =cut
151              
152             my %data_2022_ssb = (
153             worksheet_line_count => 18,
154             ssa_percentage => 0.5,
155             percentage_a => 0.85,
156             percentage_b => 0.85,
157             percentage_c => 0.85,
158             married_amt_a => 32000,
159             single_amt_a => 25000,
160             married_amt_b => 12000,
161             single_amt_b => 9000,
162             other_percentage => 0.5,
163             );
164             # inspection of 2023 Soc Sec worksheet indicates no change in
165             # parameters
166             my %data_2023_ssb = map { $_ => $data_2022_ssb{$_} } keys %data_2022_ssb;
167             # inspection of 2024 Soc Sec worksheet indicates no change in
168             # parameters
169             my %data_2024_ssb = map { $_ => $data_2023_ssb{$_} } keys %data_2023_ssb;
170             # inspection of 2025 Soc Sec worksheet indicates no change in
171             # parameters
172             my %data_2025_ssb = map { $_ => $data_2024_ssb{$_} } keys %data_2024_ssb;
173              
174             our %params = (
175             ssb => {
176             2022 => { %data_2022_ssb },
177             2023 => { %data_2023_ssb },
178             2024 => { %data_2024_ssb },
179             2025 => { %data_2025_ssb },
180             },
181             qd => {
182             2022 => {
183             worksheet_line_count => 21,
184             single_or_married_sep_amt_a => 41675,
185             married_amt_a => 83350,
186             head_of_household_amt_a => 55800,
187             single_amt_b => 459750,
188             married_sep_amt_b => 258600,
189             married_amt_b => 517200,
190             head_of_household_amt_b => 488500,
191             percentage_a => 0.15,
192             percentage_b => 0.20,
193             },
194             2023 => {
195             worksheet_line_count => 21,
196             single_or_married_sep_amt_a => 44625,
197             married_amt_a => 89250,
198             head_of_household_amt_a => 59750,
199             single_amt_b => 492300,
200             married_sep_amt_b => 276900,
201             married_amt_b => 553850,
202             head_of_household_amt_b => 523050,
203             percentage_a => 0.15,
204             percentage_b => 0.20,
205             },
206             2024 => {
207             worksheet_line_count => 21,
208             single_or_married_sep_amt_a => 47025,
209             married_amt_a => 94050,
210             head_of_household_amt_a => 63000,
211             single_amt_b => 518900,
212             married_sep_amt_b => 291850,
213             married_amt_b => 583750,
214             head_of_household_amt_b => 551350,
215             percentage_a => 0.15,
216             percentage_b => 0.20,
217             },
218             2025 => {
219             worksheet_line_count => 21,
220             single_or_married_sep_amt_a => 48350,
221             married_amt_a => 96700,
222             head_of_household_amt_a => 64750,
223             single_amt_b => 533400,
224             married_sep_amt_b => 300000,
225             married_amt_b => 600050,
226             head_of_household_amt_b => 566700,
227             percentage_a => 0.15,
228             percentage_b => 0.20,
229             },
230             },
231             );
232              
233             sub social_security_benefits {
234 39     39 1 729762 my ($inputs) = @_;
235 39         103 my $rv = _social_security_benefits_engine($inputs);
236 32         174 return $rv->{taxable_benefits};
237             }
238              
239             =head2 C
240              
241             =over 4
242              
243             =item * Purpose
244              
245             Calculate data needed for the purpose of completing all entries (except
246             checkboxes) on the Social Security Benefits Worksheet.
247              
248             my $worksheet_data = social_security_worksheet_data( $inputs );
249              
250             =item * Arguments
251              
252             The same, single hash reference which is supplied to
253             C (I above).
254              
255             =item * Return Value
256              
257             Reference to an array holding the data to be entered on lines 1-18 of the SSBW.
258             The indexes to the elements of that array correspond to those line numbers on the SSBW.
259              
260             =back
261              
262             =cut
263              
264             sub social_security_worksheet_data {
265 38     38 1 2642 my ($inputs) = @_;
266 38         134 my $rv = _social_security_benefits_engine($inputs);
267 34         171 return $rv->{worksheet_data};
268             }
269              
270             sub _social_security_benefits_engine {
271 77     77   146 my ($inputs) = @_;
272 77 100       653 croak "Argument to social_security_benefits() must be hashref"
273             unless ref($inputs) eq 'HASH';
274              
275             croak "Must include 4-digit value for 'filing_year' in argument to social_security_benefits()"
276 75 100       317 unless $inputs->{filing_year};
277 74         172 my $filing_year = $inputs->{filing_year}; # TODO add test for numeric; required element
278             croak "Must include 4-digit value for 'filing_year' in argument to social_security_benefits()"
279 74 100       494 unless $inputs->{filing_year} =~ m/^\d{4}$/;
280 73 100       328 croak "'filing_year' must be > 2000" unless $inputs->{filing_year} > 2000;
281              
282 72 100       373 my @numerics = (
283             qw(
284             box5
285             l1z
286             l2b
287             l3b
288             l4b
289             l5b
290             ),
291             $filing_year <= 2024 ? 'l7' : 'l7a',
292             qw(
293             l8
294             l2a
295             s1l11 s1l12 s1l13 s1l14 s1l15
296             s1l16 s1l17 s1l18 s1l19 s1l20
297             s1l23
298             s1l25
299             ),
300             );
301 72         169 my %permitted = map { $_ => 1 } (@numerics, 'status', 'filing_year');
  1656         3003  
302 72         197 for my $k (keys %{$inputs}) {
  72         375  
303             croak "Invalid element in hashref passed to social_security_benefits()"
304 1409 100       2987 unless $permitted{$k};
305             }
306 70         210 my %permitted_statuses = map { $_ => 1 } ( qw|
  210         555  
307             married single married_sep
308             | );
309             croak "Invalid value for 'status' element"
310 70 100 100     739 unless (defined $inputs->{status} and $permitted_statuses{$inputs->{status}});
311 66         114 my $data = {};
312 66         136 for my $el (@numerics) {
313 1386   100     3453 $data->{$el} = $inputs->{$el} // 0;
314             }
315 66         186 $data->{status} = $inputs->{status};
316 66         389 my @lines = (undef, (undef) x $params{ssb}{$filing_year}{worksheet_line_count});
317 66         112 my $formatted_lines;
318 66         112 $lines[1] = $data->{box5};
319 66         180 $lines[2] = $lines[1] * $params{ssb}{$filing_year}{ssa_percentage};
320             $lines[3] =
321             $data->{l1z} +
322             $data->{l2b} +
323             $data->{l3b} +
324             $data->{l4b} +
325             $data->{l5b} +
326             ($filing_year <= 2024 ? $data->{l7} : $data->{l7a}) +
327 66 100       284 $data->{l8};
328 66         107 $lines[4] = $data->{l2a};
329 66         142 $lines[5] = $lines[2] + $lines[3] + $lines[4];
330             # sum up some Adjustments to Income (Schedule 1, Part II)
331             $lines[6] =
332             $data->{s1l11} +
333             $data->{s1l12} +
334             $data->{s1l13} +
335             $data->{s1l14} +
336             $data->{s1l15} +
337             $data->{s1l16} +
338             $data->{s1l17} +
339             $data->{s1l18} +
340             $data->{s1l19} +
341             $data->{s1l20} +
342             $data->{s1l23} +
343 66         183 $data->{s1l25};
344 66 100       153 if (! ($lines[6] < $lines[5]) ) {
345 8         34 $formatted_lines = decimal_lines(\@lines);
346             return {
347 8         83 taxable_benefits => 0,
348             worksheet_data => $formatted_lines,
349             };
350             }
351 58         102 $lines[7] = $lines[5] - $lines[6];
352 58 100       1421 if ($data->{status} eq 'married_sep') {
353 8         21 $lines[16] = $lines[7] * $params{ssb}{$filing_year}{percentage_b};
354 8         17 $lines[17] = $lines[1] * $params{ssb}{$filing_year}{percentage_c};
355 8         31 $lines[18] = min($lines[16], $lines[17]);
356 8         25 $formatted_lines = decimal_lines(\@lines);
357             return {
358 8         83 taxable_benefits => $lines[18],
359             worksheet_data => $formatted_lines,
360             };
361             }
362             $lines[8] = $data->{status} eq 'married'
363             ? $params{ssb}{$filing_year}{married_amt_a}
364 50 100       168 : $params{ssb}{$filing_year}{single_amt_a};
365 50 100       132 unless ($lines[8] < $lines[7]) {
366 8         23 $formatted_lines = decimal_lines(\@lines);
367             return {
368 8         82 taxable_benefits => 0,
369             worksheet_data => $formatted_lines,
370             };
371             }
372 42         80 $lines[9] = $lines[7] - $lines[8];
373             $lines[10] = $data->{status} eq 'married'
374             ? $params{ssb}{$filing_year}{married_amt_b}
375 42 100       133 : $params{ssb}{$filing_year}{single_amt_b};
376 42         83 my $diff = $lines[9] - $lines[10];
377 42 100       114 $lines[11] = $diff > 0 ? $diff : 0;
378 42         155 $lines[12] = min($lines[9], $lines[10]);
379 42         116 $lines[13] = $lines[12] * $params{ssb}{$filing_year}{other_percentage};
380 42         103 $lines[14] = min($lines[2], $lines[13]);
381 42         121 my $x = $lines[11] * $params{ssb}{$filing_year}{percentage_a};
382 42 100       126 $lines[15] = $x > 0 ? $x : 0;
383 42         81 $lines[16] = $lines[14] + $lines[15];
384 42         86 $lines[17] = $lines[1] * $params{ssb}{$filing_year}{percentage_c};
385 42         101 $lines[18] = min($lines[16], $lines[17]);
386 42         123 $formatted_lines = decimal_lines(\@lines);
387             return {
388 42         609 taxable_benefits => $lines[18],
389             worksheet_data => $formatted_lines,
390             };
391             }
392              
393             =head2 C
394              
395             =over 4
396              
397             =item * Purpose
398              
399             Pretty-print ('pp' for short) the results of
400             C for easier transcription to printed
401             worksheet.
402              
403             pp_ssbw($results);
404              
405             =item * Arguments
406              
407             The array reference which is the return value of
408             C. Required.
409              
410             =item * Return Value
411              
412             Implicitly returns true value upon success.
413              
414             =item * Comment
415              
416             In a future version of this library, this function may take a second argument
417             which presumably will be a string holding the path to an output file. For
418             now, the function simply prints to C.
419              
420             =back
421              
422             =cut
423              
424             sub _compose_worksheet_line {
425 57     57   126 my ($line_number, $formatting, $text, $result) = @_;
426 57         325 my $line = sprintf("$formatting" => (
427             $line_number,
428             $text,
429             $line_number,
430             $result,
431             ) );
432 57         195 return $line;
433             }
434              
435             sub pp_ssbw {
436 3     3 1 205488 my ($results) = @_;
437 3 100       240 croak "First argument to pp_ssbw() must be array reference"
438             unless ref($results) eq 'ARRAY';
439 2         5 my @output = ();
440 2         5 my $line_number = 0;
441 2         5 my $one_wide_format = "% 2s. %-40s % 2s. % 12.2f";
442 2         4 my $two_wide_format = "% 2s. %-52s % 2s. % 12.2f";
443 2         7 my @f = (undef, $one_wide_format, $two_wide_format);
444              
445 2         62 my $lines = [
446             undef,
447             { formatting => $f[1], text => "Enter sum of 1099s, box 5" },
448             { formatting => $f[2], text => "Line 1 x 50%" },
449             { formatting => $f[2], text => "Sum of 1040 lines 1z 2b 3b 4b 5b 7/7a 8" },
450             { formatting => $f[2], text => "1040 line 2a" },
451             { formatting => $f[2], text => "Line 2 + Line 3 + Line 4" },
452             { formatting => $f[2], text => "Schedule 1, sum lines 11-20, 23, 25" },
453             { formatting => $f[2], text => "Line 5 - Line 6 (or 0)" },
454             { formatting => $f[2], text => "Status (1)" },
455             { formatting => $f[2], text => "Line 7 - Line 8 (or 0)" },
456             { formatting => $f[2], text => "Status (2)" },
457             { formatting => $f[2], text => "Line 9 - Line 10" },
458             { formatting => $f[2], text => "Smaller of lines 9 or 10" },
459             { formatting => $f[2], text => "Line 12 x 50%" },
460             { formatting => $f[2], text => "Smaller of lines 2 or 13" },
461             { formatting => $f[2], text => "Line 11 x 85%" },
462             { formatting => $f[2], text => "Line 14 + Line 15" },
463             { formatting => $f[2], text => "Line 1 x 85%" },
464             { formatting => $f[2], text => "Smaller of lines 16 or 17" },
465             ];
466              
467 2         7 for (my $i = 0; $i <= $#{$results} -1 ; $i++) {
  38         91  
468 36         64 my $j = $i + 1;
469             push @output, _compose_worksheet_line(
470             $j,
471             $lines->[$j]->{formatting},
472             $lines->[$j]->{text},
473 36         86 $results->[$j],
474             );
475             }
476              
477 2         106 say $_ for @output;
478 2         27 return 1;
479             }
480              
481             #######################################
482              
483             =head2 C
484              
485             =over 4
486              
487             =item * Purpose
488              
489             B of taxes due per the QDCGTW for the purpose of
490             entering the amount of such taxes due on IRS Form 1040. (For filing
491             year 2025, the relevant line on Form 1040 would be line 16.)
492              
493             my $lines = qualified_dividends_capital_gains_tax( $inputs );
494              
495             =item * Arguments
496              
497             Reference to a hash with 6 required elements: C.
498              
499             my $inputs = {
500             l15 => 7000.00, # Form 1040, line 15
501             l3a => 4900.00, # Form 1040, line 3a
502             sD => 1600.00, # If filing Schedule D, enter smaller
503             # of Schedule D, line 15 or 16;
504             # if not, enter Form 1040, line 7a.
505             status1 => 'single_or_married_sep', # Permissible values:
506             # single_or_married_sep
507             # married
508             # head_of_household
509             status2 => 'single', # Permissible values:
510             # single
511             # married_sep
512             # married
513             # head_of_household
514             filing_year => 2025,
515             };
516              
517             =item * Return Value
518              
519             Reference to an array where the indices of the array correspond to the values
520             calculated for the following lines in the Qualified Dividends and Capital Gain
521             Tax Worksheet:
522              
523             my $lines = [
524             undef,
525             7000, # QDCGT Worksheet, line 1
526             4900,
527             1600,
528             6500,
529             500,
530             41675,
531             7000,
532             500,
533             6500,
534             6500,
535             6500,
536             0,
537             459750,
538             7000,
539             7000,
540             0,
541             0,
542             0,
543             6500,
544             0,
545             0, # QDCGT Worksheet, line 21
546             ]
547              
548             =item * Comment
549              
550             QDCGT Worksheet lines 22 and 24 require looking up values in the Tax Table or
551             the Tax Computation Worksheet. To access the data those tables is currently
552             beyond the scope of this library. Hence, the return value of this function
553             provides you with those values you need to fill in lines 1 through 21 on the
554             Worksheet. You must then turn to the Tax Table or Tax Computation Worksheet
555             to make entries in lines 22 through 25 of the Worksheet. Once you calculate
556             line 25 of that Worksheet, you will typically enter that on Form 1040 Line 16,
557             your tax due.
558              
559             =back
560              
561             =cut
562              
563             sub qualified_dividends_capital_gains_tax {
564 63     63 1 919173 my $inputs = shift;
565 63 100       1189 croak "Argument to qualified_dividends_capital_gains_tax() must be hashref"
566             unless ref($inputs) eq 'HASH';
567 59         183 my @numerics = qw(
568             l15
569             l3a
570             sD
571             );
572              
573 59         153 my %permitted_statuses_1 = map { $_ => 1 } ( qw|
  177         608  
574             single_or_married_sep
575             married
576             head_of_household
577             | );
578             croak "Invalid value for 'status1' element"
579 59 100 100     2486 unless (defined $inputs->{status1} and $permitted_statuses_1{$inputs->{status1}});
580              
581 43         103 my %permitted_statuses_2 = map { $_ => 1 } ( qw|
  172         420  
582             single
583             married_sep
584             married
585             head_of_household
586             | );
587             croak "Invalid value for 'status2' element"
588 43 100 100     1489 unless (defined $inputs->{status2} and $permitted_statuses_2{$inputs->{status2}});
589              
590 35         94 my %permitted = map { $_ => 1 } (@numerics, 'status1', 'status2', 'filing_year');
  210         524  
591 35         92 for my $k (keys %{$inputs}) {
  35         150  
592             croak "Invalid element in hashref passed to qualified_dividends_capital_gains_tax()"
593 191 100       1078 unless $permitted{$k};
594             }
595              
596 31         104 my $data = {};
597 31         84 for my $el (@numerics) {
598 93   100     281 $inputs->{$el} //= 0;
599 93         226 $data->{$el} = $inputs->{$el};
600             }
601 31         94 $data->{status1} = $inputs->{status1};
602 31         115 $data->{status2} = $inputs->{status2};
603 31         89 my $filing_year = $inputs->{filing_year}; # TODO add test for numeric; required element
604 31         209 my @lines = (undef, (undef) x $params{qd}{$filing_year}{worksheet_line_count});
605             # We will return after line 21 because thereafter we have to look up
606             # things in the Tax Table.
607 31         76 $lines[1] = $inputs->{l15};
608 31         89 $lines[2] = $inputs->{l3a};
609 31         65 $lines[3] = $inputs->{sD};
610 31         96 $lines[4] = $lines[2] + $lines[3];
611 31         98 my $diff = $lines[1] - $lines[4];
612 31 100       105 $lines[5] = $diff > 0 ? $diff : 0;
613             $lines[6] = $inputs->{status1} eq 'single_or_married_sep'
614             ? $params{qd}{$filing_year}{single_or_married_sep_amt_a}
615             : $inputs->{status1} eq 'married'
616             ? $params{qd}{$filing_year}{married_amt_a}
617 31 100       149 : $params{qd}{$filing_year}{head_of_household_amt_a};
    100          
618 31         154 $lines[7] = min($lines[1], $lines[6]);
619 31         115 $lines[8] = min($lines[5], $lines[7]);
620 31         70 $lines[9] = $lines[7] - $lines[8];
621 31         85 $lines[10] = min($lines[1], $lines[4]);
622 31         55 $lines[11] = $lines[9];
623 31         62 $lines[12] = $lines[10] - $lines[11];
624             $lines[13] = $inputs->{status2} eq 'single'
625             ? $params{qd}{$filing_year}{single_amt_b}
626             : $inputs->{status2} eq 'married_sep'
627             ? $params{qd}{$filing_year}{married_sep_amt_b}
628             : $inputs->{status2} eq 'married'
629             ? $params{qd}{$filing_year}{married_amt_b}
630 31 100       149 : $params{qd}{$filing_year}{head_of_household_amt_b};
    100          
    100          
631 31         2451 $lines[14] = min($lines[1], $lines[13]);
632 31         90 $lines[15] = $lines[5] + $lines[9];
633 31         63 my $diff1 = $lines[14] - $lines[15];
634 31 100       85 $lines[16] = $diff1 > 0 ? $diff1 : 0;
635 31         120 $lines[17] = min($lines[12], $lines[16]);
636 31         198 $lines[18] = $lines[17] * $params{qd}{$filing_year}{percentage_a};
637 31         91 $lines[19] = $lines[9] + $lines[17];
638 31         67 $lines[20] = $lines[10] - $lines[19];
639 31         86 $lines[21] = $lines[20] * $params{qd}{$filing_year}{percentage_b};
640             # We will need to use 5, 18, 21, 22 and 1
641             my @formatted_lines = (
642             $lines[0], # undef
643 31         154 map { sprintf("%.2f" => $lines[$_]) } (1..$#lines),
  651         2674  
644             );
645 31         355 return \@formatted_lines;
646             }
647              
648             =head2 C
649              
650             =over 4
651              
652             =item * Purpose
653              
654             Pretty-print ('pp' for short) the results of
655             C for easier transcription to printed
656             worksheet.
657              
658             pp_qdcgtw($results);
659              
660             =item * Arguments
661              
662             The array reference which is the return value of
663             C. Required.
664              
665             =item * Return Value
666              
667             Implicitly returns true value upon success.
668              
669             =item * Comment
670              
671             In a future version of this library, this function may take a second argument
672             which presumably will be a string holding the path to an output file. For
673             now, the function simply prints to C.
674              
675             =back
676              
677             =cut
678              
679             sub pp_qdcgtw {
680 2     2 1 221036 my ($results) = @_;
681 2 100       227 croak "First argument to pp_qdcgtw() must be array reference"
682             unless ref($results) eq 'ARRAY';
683 1         3 my @output = ();
684 1         3 my $line_number = 0;
685 1         3 my $one_wide_format = "% 2s. %-28s % 2s. % 12.2f";
686 1         3 my $two_wide_format = "% 2s. %-40s % 2s. % 12.2f";
687 1         2 my $three_wide_format = "% 2s. %-52s % 2s. % 12.2f";
688 1         4 my @f = (undef, $one_wide_format, $two_wide_format, $three_wide_format);
689              
690 1         30 my $lines = [
691             undef,
692             { formatting => $f[2], text => "Enter Form 1040, line 15" },
693             { formatting => $f[1], text => "Enter Form 1040, line 3a" },
694             { formatting => $f[1], text => "Sche. D/Form 1040, line 7/7a" },
695             { formatting => $f[1], text => "Line 2 - Line 3" },
696             { formatting => $f[2], text => "Line 1 - Line 4" },
697             { formatting => $f[2], text => "Filing status amount (1)" },
698             { formatting => $f[2], text => "Smaller of lines 1 or 6" },
699             { formatting => $f[2], text => "Smaller of lines 5 or 7" },
700             { formatting => $f[2], text => "Line 7 - Line 8" },
701             { formatting => $f[2], text => "Smaller of lines 1 or 4" },
702             { formatting => $f[2], text => "Line 9 amount" },
703             { formatting => $f[2], text => "Line 10 - Line 11" },
704             { formatting => $f[2], text => "Filing status amount (2)" },
705             { formatting => $f[2], text => "Smaller of lines 1 or 13" },
706             { formatting => $f[2], text => "Line 5 + Line 9" },
707             { formatting => $f[2], text => "Line 14 - Line 15" },
708             { formatting => $f[2], text => "Smaller of lines 12 or 16" },
709             { formatting => $f[3], text => "Line 17 x 15%" },
710             { formatting => $f[2], text => "Line 9 + Line 17" },
711             { formatting => $f[2], text => "Line 10 - Line 19" },
712             { formatting => $f[3], text => "Line 20 x 20%" },
713             ];
714              
715 1         9 for (my $i = 0; $i <= $#{$results} -1 ; $i++) {
  22         57  
716 21         41 my $j = $i + 1;
717             push @output, _compose_worksheet_line(
718             $j,
719             $lines->[$j]->{formatting},
720             $lines->[$j]->{text},
721 21         50 $results->[$j],
722             );
723             }
724              
725 1         72 say $_ for @output;
726 1         15 return 1;
727             }
728              
729             =head2 C
730              
731             =over 4
732              
733             =item * Purpose
734              
735             This is a helper subroutine used within both this module and the test suite to
736             ensure that all final monetary data is appropriately reported to two decimal
737             places.
738              
739             =item * Arguments
740              
741             my $formatted_lines = decimal_lines($lines);
742              
743             Single array reference holding a list of the values calculated for the various
744             lines in a worksheet.
745              
746             =item * Return Value
747              
748             Single array reference holding a list of values prepared for entry into the
749             worksheets to two decimal places (except for where the value is zero (C<0>).
750             Values that are undefined remain so.
751              
752             =back
753              
754             =cut
755              
756             sub decimal_lines {
757 100     100 1 32171 my $lines = shift;
758 100         171 my @formatted_lines = ();
759 100         145 for my $l (@{$lines}) {
  100         209  
760 1900 100 100     5665 if (! defined $l or $l eq '0') {
761 672         1199 push @formatted_lines, $l;
762             }
763             else {
764 1228         4682 push @formatted_lines, sprintf("%.2f" => $l);
765             }
766             }
767 100         306 return \@formatted_lines;
768             }
769              
770             =head1 AUTHOR
771              
772             James E Keenan
773             CPAN ID: JKEENAN
774             jkeenan@cpan.org
775             http://thenceforward.net/perl
776              
777             =head1 COPYRIGHT
778              
779             This program is free software; you can redistribute
780             it and/or modify it under the same terms as Perl itself.
781              
782             The full text of the license can be found in the
783             LICENSE file included with this module.
784              
785             =head1 SEE ALSO
786              
787             perl(1).
788              
789             =cut
790              
791             1;
792             # The preceding line will help the module return a true value
793