File Coverage

blib/lib/Finance/Tax/Aruba/Role/Income/TaxYear.pm
Criterion Covered Total %
statement 87 91 95.6
branch 7 8 87.5
condition n/a
subroutine 36 38 94.7
pod 0 20 0.0
total 130 157 82.8


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