File Coverage

blib/lib/Finance/Tax/Aruba/Role/Income/TaxYear.pm
Criterion Covered Total %
statement 88 92 95.6
branch 7 8 87.5
condition n/a
subroutine 37 39 94.8
pod 0 20 0.0
total 132 159 83.0


line stmt bran cond sub pod time code
1             package Finance::Tax::Aruba::Role::Income::TaxYear;
2             our $VERSION = '0.009';
3 4     4   4551 use Moose::Role;
  4         20150  
  4         15  
4              
5             # ABSTRACT: A role that implements income tax logic
6              
7             requires qw(
8             _build_tax_bracket
9             is_year
10             );
11              
12             has children => (
13             is => 'ro',
14             isa => 'Int',
15             default => 0,
16             );
17              
18             has dependents => (
19             is => 'ro',
20             isa => 'Int',
21             default => 0,
22             );
23              
24             has children_study_abroad => (
25             is => 'ro',
26             isa => 'Int',
27             default => 0,
28             );
29              
30             # Child (<18) not going to school
31             has child_deduction_amount => (
32             is => 'ro',
33             isa => 'Num',
34             default => 700,
35             );
36              
37             # School going > 16 < 27 with severe handicap which is unable
38             # to work
39             has dependent_deduction_amount => (
40             is => 'ro',
41             isa => 'Num',
42             default => 1200,
43             );
44              
45             has additional_deduction_amount => (
46             is => 'ro',
47             isa => 'Num',
48             default => 3800,
49             );
50              
51             has pension_employee_perc => (
52             is => 'ro',
53             isa => 'Num',
54             default => 3,
55             );
56              
57             has pension_employer_perc => (
58             is => 'ro',
59             isa => 'Num',
60             default => 3,
61             );
62              
63             has income => (
64             is => 'ro',
65             isa => 'Num',
66             required => 1,
67             );
68              
69             has yearly_income => (
70             is => 'ro',
71             isa => 'Num',
72             lazy => 1,
73             builder => '_build_yearly_income',
74             predicate => 'has_yearly_income',
75             init_arg => undef,
76             );
77              
78             has pension_employee => (
79             is => 'ro',
80             isa => 'Num',
81             lazy => 1,
82             builder => '_build_pension_employee',
83             predicate => 'has_pension_employee',
84             init_arg => undef,
85             );
86              
87             has pension_employer => (
88             is => 'ro',
89             isa => 'Num',
90             lazy => 1,
91             builder => '_build_pension_employer',
92             predicate => 'has_pension_employer',
93             init_arg => undef,
94             );
95              
96             has bonus => (
97             is => 'ro',
98             isa => 'Num',
99             default => 0,
100             );
101              
102             has fringe => (
103             is => 'ro',
104             isa => 'Num',
105             default => 0,
106             );
107              
108             has tax_free => (
109             is => 'ro',
110             isa => 'Num',
111             default => 0,
112             );
113              
114             has yearly_income_gross => (
115             is => 'ro',
116             isa => 'Num',
117             lazy => 1,
118             builder => '_build_yearly_income_gross',
119             predicate => 'has_yearly_income_gross',
120             );
121              
122             has months => (
123             is => 'ro',
124             isa => 'Int',
125             default => 12,
126             );
127              
128             has wervingskosten_max => (
129             is => 'ro',
130             isa => 'Num',
131             default => 1500,
132             );
133              
134             has wervingskosten_percentage => (
135             is => 'ro',
136             isa => 'Num',
137             default => 3,
138             );
139              
140             has wervingskosten => (
141             is => 'ro',
142             isa => 'Num',
143             lazy => 1,
144             builder => '_build_wervingskosten',
145             );
146              
147             has aov_max => (
148             is => 'ro',
149             isa => 'Num',
150             default => 85_000,
151             );
152              
153             has azv_max => (
154             is => 'ro',
155             isa => 'Num',
156             default => 85_000,
157             );
158              
159             has taxfree_max => (
160             is => 'ro',
161             isa => 'Num',
162             default => 28_861,
163             );
164              
165             has taxfree_amount => (
166             is => 'ro',
167             isa => 'Num',
168             builder => '_build_taxfree_amount',
169             lazy => 1,
170             );
171              
172             has aov_percentage_employer => (
173             is => 'ro',
174             isa => 'Num',
175             default => 10.5,
176             );
177              
178             has aov_percentage_employee => (
179             is => 'ro',
180             isa => 'Num',
181             default => 5,
182             );
183              
184             has aov_yearly_income => (
185             is => 'ro',
186             isa => 'Num',
187             lazy => 1,
188             builder => '_get_aov_yearly_income',
189             );
190              
191             has azv_max => (
192             is => 'ro',
193             isa => 'Num',
194             default => 85_000,
195             );
196              
197             has azv_percentage_employee => (
198             is => 'ro',
199             isa => 'Num',
200             default => 1.6,
201             );
202              
203             has azv_percentage_employer => (
204             is => 'ro',
205             isa => 'Num',
206             default => 8.9,
207             );
208              
209             has azv_yearly_income => (
210             is => 'ro',
211             isa => 'Num',
212             lazy => 1,
213             builder => '_get_aov_yearly_income',
214             );
215              
216             has tax_brackets => (
217             is => 'ro',
218             isa => 'ArrayRef',
219             lazy => 1,
220             builder => '_build_tax_bracket',
221             );
222              
223             has tax_bracket => (
224             is => 'ro',
225             isa => 'HashRef',
226             lazy => 1,
227             builder => '_get_tax_bracket',
228             );
229              
230             has tax_rate => (
231             is => 'ro',
232             isa => 'Num',
233             lazy => 1,
234             builder => '_get_tax_rate',
235             );
236              
237             has tax_fixed => (
238             is => 'ro',
239             isa => 'Num',
240             lazy => 1,
241             builder => '_get_tax_fixed',
242             );
243              
244             has tax_minimum => (
245             is => 'ro',
246             isa => 'Num',
247             lazy => 1,
248             builder => '_get_tax_minimum',
249             );
250              
251             has tax_maximum => (
252             is => 'ro',
253             isa => 'Defined',
254             lazy => 1,
255             builder => '_get_tax_maximum',
256             );
257              
258             has tax_variable => (
259             is => 'ro',
260             isa => 'Num',
261             lazy => 1,
262             builder => '_get_tax_variable',
263             );
264              
265             has taxable_amount => (
266             is => 'ro',
267             isa => 'Num',
268             lazy => 1,
269             builder => '_get_taxable_amount',
270             );
271              
272             sub _get_max {
273 75     75   190 my ($max, $value) = @_;
274 75 100       2654 return $value > $max ? $max : $value;
275             }
276              
277             sub _build_pension_employee {
278 25     25   56 my $self = shift;
279 25         935 return $self->get_cost($self->yearly_income_gross - $self->fringe - $self->bonus,
280             $self->pension_employee_perc);
281             }
282              
283             sub _build_pension_employer {
284 25     25   53 my $self = shift;
285 25         886 return $self->get_cost($self->yearly_income_gross - $self->fringe - $self->bonus,
286             $self->pension_employer_perc);
287             }
288              
289             sub _build_yearly_income_gross {
290 25     25   54 my $self = shift;
291 25         879 return $self->income + $self->fringe + $self->bonus;
292             }
293              
294             sub _build_yearly_income {
295 25     25   51 my $self = shift;
296 25         875 return $self->yearly_income_gross - $self->wervingskosten
297             - $self->pension_employee;
298             }
299              
300             sub _get_tax_bracket {
301 25     25   55 my $self = shift;
302              
303 25         50 foreach (@{ $self->tax_brackets }) {
  25         849  
304 56 100       132 return $_ if $self->taxable_wage < $_->{max};
305             }
306             }
307              
308             sub _get_tax_rate {
309 25     25   57 my $self = shift;
310 25         820 return $self->tax_bracket->{rate};
311             }
312              
313             sub _get_tax_fixed {
314 25     25   68 my $self = shift;
315 25         837 return $self->tax_bracket->{fixed};
316             }
317              
318             sub _get_tax_minimum {
319 25     25   50 my $self = shift;
320 25         863 return $self->tax_bracket->{min};
321             }
322              
323             sub _get_tax_maximum {
324 0     0   0 my $self = shift;
325 0         0 return $self->tax_bracket->{max} * 1;
326             }
327              
328             sub _get_taxable_amount {
329 25     25   58 my $self = shift;
330 25         104 return _format_perc($self->taxable_wage - $self->tax_minimum);
331             }
332              
333             sub _get_tax_variable {
334 25     25   54 my $self = shift;
335 25         870 return $self->get_cost($self->taxable_amount, $self->tax_rate);
336             }
337              
338             sub income_tax {
339 127     127 0 361 my $self = shift;
340 127         4531 return int($self->tax_variable + $self->tax_fixed);
341             }
342              
343             sub _build_wervingskosten {
344 25     25   54 my $self = shift;
345 25         854 my $wervingskosten = $self->get_cost($self->yearly_income_gross,
346             $self->wervingskosten_percentage);
347 25         948 return _get_max($self->wervingskosten_max, $wervingskosten);
348             }
349              
350             sub get_cost {
351 865     865 0 1929 my ($self, $costs, $perc) = @_;
352 865         2440 return _format_perc($costs * ($perc / 100));
353             }
354              
355             sub _format_perc {
356 890     890   11201 return sprintf("%.02f", shift) + 0;
357             }
358              
359             sub _build_taxfree_amount {
360 25     25   64 my $self = shift;
361              
362 25 100       66 if ($self->zuiver_jaarloon < $self->taxfree_max) {
363 4         18 return $self->zuiver_jaarloon * ($self->months / 12);
364             }
365 21         650 return $self->taxfree_max * ($self->months / 12);
366             }
367              
368             sub _get_aov_yearly_income {
369 50     50   96 my $self = shift;
370 50         1656 return _get_max($self->aov_max, $self->yearly_income);
371             }
372              
373             sub aov_employee {
374 354     354 0 22885 my $self = shift;
375 354         11943 return $self->get_cost($self->aov_yearly_income,
376             $self->aov_percentage_employee);
377             }
378              
379             sub aov_employer {
380 26     26 0 2489 my $self = shift;
381 26         866 return $self->get_cost($self->aov_yearly_income,
382             $self->aov_percentage_employer);
383             }
384              
385             sub pension_premium {
386 1     1 0 2 my $self = shift;
387 1         35 return $self->get_cost($self->yearly_income_gross - $self->fringe - $self->bonus,
388             $self->pension_employee_perc + $self->pension_employer_perc);
389             }
390              
391             sub aov_premium {
392 2     2 0 3 my $self = shift;
393 2         83 return $self->get_cost($self->aov_yearly_income,
394             $self->aov_percentage_employee + $self->aov_percentage_employer);
395             }
396              
397             sub azv_premium {
398 2     2 0 6 my $self = shift;
399 2         71 return $self->get_cost($self->azv_yearly_income,
400             $self->azv_percentage_employee + $self->azv_percentage_employer);
401             }
402              
403             sub _get_azv_yearly_income {
404 0     0   0 my $self = shift;
405 0         0 return _get_max($self->azv_max, $self->yearly_income);
406             }
407              
408             sub azv_employee {
409 354     354 0 3455 my $self = shift;
410 354         12393 return $self->get_cost($self->azv_yearly_income,
411             $self->azv_percentage_employee);
412             }
413              
414             sub azv_employer {
415 26     26 0 2516 my $self = shift;
416 26         918 return $self->get_cost($self->azv_yearly_income,
417             $self->azv_percentage_employer);
418             }
419              
420             sub net_yearly_income {
421 45     45 0 19159 my $self = shift;
422 45         134 return $self->zuiver_jaarloon;
423             }
424              
425             sub child_deductions {
426 210     210 0 2018 my $self = shift;
427              
428             return
429 210         7166 ($self->children * $self->child_deduction_amount)
430             + ($self->dependents * $self->dependent_deduction_amount)
431             + ($self->children_study_abroad * $self->additional_deduction_amount);
432             }
433              
434             sub zuiver_jaarloon {
435 208     208 0 2801 my $self = shift;
436              
437 208         7334 return $self->yearly_income - $self->aov_employee - $self->azv_employee
438             - $self->child_deductions;
439             }
440              
441             sub taxable_wage {
442 131     131 0 24846 my $self = shift;
443 131         282 my $taxable_wage = $self->zuiver_jaarloon - $self->taxfree_amount;
444 131 50       3439 return $taxable_wage < 0 ? 0 : $taxable_wage;
445             }
446              
447             sub employee_income_deductions {
448 75     75 0 251 my $self = shift;
449 75         174 return $self->aov_employee + $self->azv_employee + $self->income_tax;
450             }
451              
452             sub pension_total {
453 1     1 0 3 my $self = shift;
454 1         5 return $self->pension_premium;
455             }
456              
457             sub tax_free_wage {
458 26     26 0 926 my $self = shift;
459             return
460 26         844 $self->yearly_income
461             - $self->employee_income_deductions
462             - $self->taxfree_amount
463             - $self->fringe;
464             }
465              
466             sub net_income {
467 1     1 0 821 my $self = shift;
468             return
469 1         4 $self->tax_free_wage
470             + $self->taxfree_amount
471             + $self->wervingskosten
472             + $self->tax_free;
473             }
474              
475             sub company_costs {
476 1     1 0 790 my $self = shift;
477             return
478 1         43 $self->yearly_income_gross
479             + $self->aov_employer
480             + $self->azv_employer
481             + $self->pension_employer;
482             }
483              
484             sub government_costs {
485 2     2 0 824 my $self = shift;
486 2         8 return $self->aov_premium + $self->azv_premium + $self->income_tax
487             }
488              
489             sub social_costs {
490 1     1 0 784 my $self = shift;
491 1         4 return $self->government_costs + $self->pension_total;
492             }
493              
494             around BUILDARGS => sub {
495             my $orig = shift;
496             my $self = shift;
497             my %args = @_;
498              
499             foreach (qw(income fringe tax-free)) {
500             next unless exists $args{$_};
501             $args{$_} *= ($args{months} // 12);
502             }
503              
504             if ($args{as_np}) {
505             $args{pension_employer_perc} = 0;
506             $args{pension_employee_perc} = 0;
507              
508             $self->_offset_values('aov_percentage_employer', 0,
509             'aov_percentage_employee', \%args);
510             $self->_offset_values('azv_percentage_employer', 0,
511             'azv_percentage_employee', \%args);
512             return $self->$orig(%args);
513             }
514              
515             if ($args{premiums_employer}) {
516             $self->_offset_values('aov_percentage_employee', 0,
517             'aov_percentage_employer', \%args);
518             $self->_offset_values('azv_percentage_employee', 0,
519             'azv_percentage_employer', \%args);
520             $args{pension_by_employer} = 1;
521             }
522             else {
523             if ($args{azv_by_employer}) {
524             $self->_offset_values(
525             'azv_percentage_employee', 0,
526             'azv_percentage_employer', \%args
527             );
528             }
529              
530             if ($args{aov_by_employer}) {
531             $self->_offset_values(
532             'aov_percentage_employee', 0,
533             'aov_percentage_employer', \%args
534             );
535             }
536             }
537              
538             if ($args{no_pension}) {
539             $args{pension_employer_perc} = 0;
540             $args{pension_employee_perc} = 0;
541             }
542             elsif ($args{pension_by_employer}) {
543             $self->_offset_values(
544             'pension_employee_perc', 0,
545             'pension_employer_perc', \%args
546             );
547             }
548             elsif (exists $args{pension_employee_perc}) {
549             $self->_offset_values('pension_employee_perc',
550             $args{pension_employee_perc},
551             'pension_employer_perc', \%args);
552             }
553             elsif (exists $args{pension_employer_perc}) {
554             $self->_offset_values('pension_employer_perc',
555             $args{pension_employer_perc},
556             'pension_employee_perc', \%args);
557             }
558              
559             return $self->$orig(%args);
560              
561             };
562              
563             sub _offset_values {
564 7     7   16 my $self = shift;
565 7         35 my $source = $self->meta->find_attribute_by_name(shift);
566 7         761 my $value = shift;
567 7         22 my $target = $self->meta->find_attribute_by_name(shift);
568 7         425 my $args = shift;
569              
570 7         58 my $diff = $value - $source->default;
571 7         70 my $t = $target->default + (-1 * $diff);
572              
573 7         88 $args->{ $source->name } = $value;
574 7         30 $args->{ $target->name } = $t;
575 7         17 return;
576             }
577              
578             1;
579              
580             __END__
581              
582             =pod
583              
584             =encoding UTF-8
585              
586             =head1 NAME
587              
588             Finance::Tax::Aruba::Role::Income::TaxYear - A role that implements income tax logic
589              
590             =head1 VERSION
591              
592             version 0.009
593              
594             =head1 SYNOPSIS
595              
596             package Aruba::Tax::Income::XXXX;
597             use Moose;
598              
599             with qw(Finance::Tax::Aruba::Role::Income::TaxYear);
600              
601             sub _build_tax_bracket {
602             return [],
603             }
604              
605             sub is_year {
606             ...;
607             }
608              
609             =head1 DESCRIPTION
610              
611             Consumers of this role must implements the following methods:
612              
613             =head2 _build_tax_bracket
614              
615             This should be an array reference containing the information about each
616             bracket.
617              
618             [
619             { min => 0, max => 34930, fixed => 0, rate => 14 },
620             {
621             min => 34930,
622             max => 65904,
623             fixed => 4890.2,
624             rate => 25
625             },
626             {
627             min => 65904,
628             max => 147454,
629             fixed => 12633.7,
630             rate => 42
631             },
632             {
633             min => 147454,
634             max => 'inf' * 1,
635             fixed => 46884.7,
636             rate => 52
637             },
638             ];
639              
640             =head2 is_year
641              
642             This function should return true if the year is supported by the plugin
643              
644             =head1 ATTRIBUTES
645              
646             TODO: Add more documentation
647              
648             =head1 AUTHOR
649              
650             Wesley Schwengle <waterkip@cpan.org>
651              
652             =head1 COPYRIGHT AND LICENSE
653              
654             This software is Copyright (c) 2020 by Wesley Schwengle.
655              
656             This is free software, licensed under:
657              
658             The (three-clause) BSD License
659              
660             =cut