File Coverage

blib/lib/Finance/Tax/Aruba/Role/Income/TaxYear.pm
Criterion Covered Total %
statement 73 87 83.9
branch 7 8 87.5
condition n/a
subroutine 29 36 80.5
pod 0 18 0.0
total 109 149 73.1


line stmt bran cond sub pod time code
1             package Finance::Tax::Aruba::Role::Income::TaxYear;
2             our $VERSION = '0.007';
3 4     4   4819 use Moose::Role;
  4         20564  
  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             sub _get_max {
115 72     72   172 my ($max, $value) = @_;
116 72 100       3213 return $value > $max ? $max : $value;
117             }
118              
119             sub _build_pension_employee {
120 24     24   58 my $self = shift;
121 24         825 return $self->get_cost($self->yearly_income_gross - $self->fringe,
122             $self->pension_employee_perc);
123             }
124              
125             sub _build_pension_employer {
126 24     24   49 my $self = shift;
127 24         845 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 24     24   55 my $self = shift;
291 24         836 return $self->income + $self->fringe;
292             }
293              
294             sub _build_yearly_income {
295 24     24   55 my $self = shift;
296 24         814 return $self->yearly_income_gross - $self->wervingskosten
297             - $self->pension_employee + $self->bonus;
298             }
299              
300             sub _get_tax_bracket {
301 24     24   45 my $self = shift;
302              
303 24         47 foreach (@{ $self->tax_brackets }) {
  24         790  
304 55 100       138 return $_ if $self->taxable_wage < $_->{max};
305             }
306             }
307              
308             sub _get_tax_rate {
309 24     24   55 my $self = shift;
310 24         795 return $self->tax_bracket->{rate};
311             }
312              
313             sub _get_tax_fixed {
314 24     24   54 my $self = shift;
315 24         796 return $self->tax_bracket->{fixed};
316             }
317              
318             sub _get_tax_minimum {
319 24     24   51 my $self = shift;
320 24         774 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 24     24   49 my $self = shift;
330              
331 24         68 return sprintf("%.02f", $self->taxable_wage - $self->tax_minimum) + 0;
332             }
333              
334             sub _get_tax_variable {
335 24     24   152 my $self = shift;
336 24         1228 return $self->get_cost($self->taxable_amount, $self->tax_rate);
337             }
338              
339             sub income_tax {
340 120     120 0 330 my $self = shift;
341 120         3949 return int($self->tax_variable + $self->tax_fixed);
342             }
343              
344             sub _build_wervingskosten {
345 24     24   58 my $self = shift;
346 24         918 my $wervingskosten = $self->get_cost($self->yearly_income_gross,
347             $self->wervingskosten_percentage);
348 24         950 return _get_max($self->wervingskosten_max, $wervingskosten);
349             }
350              
351             sub get_cost {
352 824     824 0 1745 my ($self, $costs, $perc) = @_;
353 824         9929 return sprintf("%.02f", $costs * ($perc / 100)) + 0;
354             }
355              
356             sub _build_taxfree_amount {
357 24     24   53 my $self = shift;
358              
359 24 100       63 if ($self->zuiver_jaarloon < $self->taxfree_max) {
360 4         17 return $self->zuiver_jaarloon * ($self->months / 12);
361             }
362 20         621 return $self->taxfree_max * ($self->months / 12);
363             }
364              
365             sub _get_aov_yearly_income {
366 48     48   90 my $self = shift;
367 48         1562 return _get_max($self->aov_max, $self->yearly_income);
368             }
369              
370             sub aov_employee {
371 340     340 0 22652 my $self = shift;
372 340         11368 return $self->get_cost($self->aov_yearly_income,
373             $self->aov_percentage_employee);
374             }
375              
376             sub aov_employer {
377 24     24 0 2417 my $self = shift;
378 24         840 return $self->get_cost($self->aov_yearly_income,
379             $self->aov_percentage_employer);
380             }
381              
382             sub pension_premium {
383 0     0 0 0 my $self = shift;
384 0         0 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 0     0 0 0 my $self = shift;
390 0         0 return $self->get_cost($self->aov_yearly_income,
391             $self->aov_percentage_employee + $self->aov_percentage_employer);
392             }
393              
394             sub azv_premium {
395 0     0 0 0 my $self = shift;
396 0         0 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 340     340 0 3038 my $self = shift;
407 340         12038 return $self->get_cost($self->azv_yearly_income,
408             $self->azv_percentage_employee);
409             }
410              
411             sub azv_employer {
412 24     24 0 2486 my $self = shift;
413 24         846 return $self->get_cost($self->azv_yearly_income,
414             $self->azv_percentage_employer);
415             }
416              
417             sub net_yearly_income {
418 42     42 0 18545 my $self = shift;
419 42         125 return $self->zuiver_jaarloon;
420             }
421              
422             sub child_deductions {
423 202     202 0 2211 my $self = shift;
424              
425             return
426 202         6643 ($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 200     200 0 2719 my $self = shift;
433              
434 200         6963 return $self->yearly_income - $self->aov_employee - $self->azv_employee
435             - $self->child_deductions;
436             }
437              
438             sub taxable_wage {
439 127     127 0 25098 my $self = shift;
440 127         298 my $taxable_wage = $self->zuiver_jaarloon - $self->taxfree_amount;
441 127 50       2726 return $taxable_wage < 0 ? 0 : $taxable_wage;
442             }
443              
444             sub employee_income_deductions {
445 72     72 0 265 my $self = shift;
446 72         164 return $self->aov_employee + $self->azv_employee + $self->income_tax;
447             }
448              
449             sub pension_total {
450 0     0 0 0 my $self = shift;
451 0         0 return $self->pension_premium;
452             }
453              
454             sub tax_free_wage {
455 25     25 0 868 my $self = shift;
456             return
457 25         822 $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 776 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 0     0 0 0 my $self = shift;
474             return
475 0         0 $self->net_income
476             + $self->aov_premium
477             + $self->azv_premium
478             + $self->income_tax
479             + $self->pension_employer;
480             }
481              
482             around BUILDARGS => sub {
483             my $orig = shift;
484             my $self = shift;
485             my %args = @_;
486              
487             foreach (qw(income fringe tax-free)) {
488             next unless exists $args{$_};
489             $args{$_} *= ($args{months} // 12);
490             }
491              
492             if ($args{as_np}) {
493              
494             $args{pension_employer_perc} = 0;
495             $args{pension_employee_perc} = 0;
496              
497             $self->_offset_values('aov_percentage_employer', 0,
498             'aov_percentage_employee', \%args);
499             $self->_offset_values('azv_percentage_employer', 0,
500             'azv_percentage_employee', \%args);
501             return $self->$orig(%args);
502             }
503              
504              
505             if ($args{no_pension}) {
506             $args{pension_employer_perc} = 0;
507             $args{pension_employee_perc} = 0;
508             }
509             else {
510             if ($args{pension_employee_perc}) {
511             $self->_offset_values('pension_employee_perc',
512             $args{pension_employee_perc},
513             'pension_employer_perc', \%args);
514             }
515             if ($args{pension_employer_perc}) {
516             $self->_offset_values('pension_employer_perc',
517             $args{pension_employer_perc},
518             'pension_employee_perc', \%args);
519             }
520             }
521              
522             if ($args{premiums_employer}) {
523             $self->_offset_values('aov_percentage_employee', 0,
524             'aov_percentage_employer', \%args);
525             $self->_offset_values('azv_percentage_employee', 0,
526             'azv_percentage_employer', \%args);
527             }
528             else {
529             if ($args{azv_by_employer}) {
530             $self->_offset_values(
531             'azv_percentage_employee', 0,
532             'azv_percentage_employer', \%args
533             );
534             }
535              
536             if ($args{aov_by_employer}) {
537             $self->_offset_values(
538             'aov_percentage_employee', 0,
539             'aov_percentage_employer', \%args
540             );
541             }
542             }
543              
544             return $self->$orig(%args);
545              
546             };
547              
548             sub _offset_values {
549 5     5   14 my $self = shift;
550 5         28 my $source = $self->meta->find_attribute_by_name(shift);
551 5         592 my $value = shift;
552 5         22 my $target = $self->meta->find_attribute_by_name(shift);
553 5         295 my $args = shift;
554              
555 5         30 my $diff = $value - $source->default;
556 5         57 my $t = $target->default + (-1 * $diff);
557              
558 5         60 $args->{ $source->name } = $value;
559 5         22 $args->{ $target->name } = $t;
560 5         11 return;
561             }
562              
563             1;
564              
565             __END__
566              
567             =pod
568              
569             =encoding UTF-8
570              
571             =head1 NAME
572              
573             Finance::Tax::Aruba::Role::Income::TaxYear - A role that implements income tax logic
574              
575             =head1 VERSION
576              
577             version 0.007
578              
579             =head1 SYNOPSIS
580              
581             package Aruba::Tax::Income::XXXX;
582             use Moose;
583              
584             with qw(Finance::Tax::Aruba::Role::Income::TaxYear);
585              
586             sub _build_tax_bracket {
587             return [],
588             }
589              
590             sub is_year {
591             ...;
592             }
593              
594             =head1 DESCRIPTION
595              
596             Consumers of this role must implements the following methods:
597              
598             =head2 _build_tax_bracket
599              
600             This should be an array reference containing the information about each
601             bracket.
602              
603             [
604             { min => 0, max => 34930, fixed => 0, rate => 14 },
605             {
606             min => 34930,
607             max => 65904,
608             fixed => 4890.2,
609             rate => 25
610             },
611             {
612             min => 65904,
613             max => 147454,
614             fixed => 12633.7,
615             rate => 42
616             },
617             {
618             min => 147454,
619             max => 'inf' * 1,
620             fixed => 46884.7,
621             rate => 52
622             },
623             ];
624              
625             =head2 is_year
626              
627             This function should return true if the year is supported by the plugin
628              
629             =head1 ATTRIBUTES
630              
631             TODO: Add more documentation
632              
633             =head1 AUTHOR
634              
635             Wesley Schwengle <waterkip@cpan.org>
636              
637             =head1 COPYRIGHT AND LICENSE
638              
639             This software is Copyright (c) 2020 by Wesley Schwengle.
640              
641             This is free software, licensed under:
642              
643             The (three-clause) BSD License
644              
645             =cut