File Coverage

blib/lib/Business/RO/TaxDeduction.pm
Criterion Covered Total %
statement 53 53 100.0
branch 12 12 100.0
condition 5 6 83.3
subroutine 15 15 100.0
pod 1 1 100.0
total 86 87 98.8


line stmt bran cond sub pod time code
1             package Business::RO::TaxDeduction;
2             $Business::RO::TaxDeduction::VERSION = '0.012';
3             # ABSTRACT: Romanian salary tax deduction calculator
4              
5 2     2   193470 use 5.010001;
  2         49  
6 2     2   942 use utf8;
  2         23  
  2         9  
7 2     2   874 use Moo;
  2         18635  
  2         7  
8 2     2   3105 use MooX::HandlesVia;
  2         15413  
  2         10  
9 2     2   1952 use Math::BigFloat;
  2         85353  
  2         10  
10 2     2   36617 use Scalar::Util qw(blessed);
  2         4  
  2         114  
11 2         22 use Business::RO::TaxDeduction::Types qw(
12             Int
13             MathBigFloat
14 2     2   846 );
  2         6  
15 2     2   2360 use Business::RO::TaxDeduction::Amount;
  2         8  
  2         63  
16 2     2   774 use Business::RO::TaxDeduction::Ranges;
  2         5  
  2         52  
17 2     2   794 use Business::RO::TaxDeduction::Table;
  2         6  
  2         1086  
18              
19             has 'vbl' => (
20             is => 'ro',
21             isa => Int,
22             required => 1,
23             );
24              
25             has 'year' => (
26             is => 'ro',
27             isa => Int,
28             default => sub { 2018 },
29             );
30              
31             has 'persons' => (
32             is => 'ro',
33             isa => Int,
34             default => sub { 0 },
35             );
36              
37             has 'deduction' => (
38             is => 'ro',
39             lazy => 1,
40             default => sub {
41             my $self = shift;
42             return Business::RO::TaxDeduction::Amount->new(
43             year => $self->year,
44             persons => $self->persons,
45             );
46             },
47             );
48              
49             has 'ranges' => (
50             is => 'ro',
51             lazy => 1,
52             default => sub {
53             my $self = shift;
54             return Business::RO::TaxDeduction::Ranges->new(
55             year => $self->year,
56             );
57             },
58             handles => [ qw( vbl_min vbl_max f_min f_max ) ],
59             );
60              
61             has 'ten' => (
62             is => 'ro',
63             isa => MathBigFloat,
64             default => sub {
65             return Math::BigFloat->new(10);
66             },
67             );
68              
69             sub tax_deduction {
70 1341     1341 1 605442 my $self = shift;
71 1341         3636 my $vbl = $self->_round_to_int( $self->vbl );
72              
73 1341 100       3682 return $self->_amount_for_2018 if $self->year >= 2018;
74              
75 990         18303 my $amount = $self->deduction->amount;
76 990 100 66     119513 if ( $vbl <= $self->vbl_min ) {
    100          
77 10         410 return $amount;
78             }
79             elsif ( ( $vbl > $self->vbl_min ) && ( $vbl <= $self->vbl_max ) ) {
80 970         34267 $amount = $self->_tax_deduction_formula($vbl, $amount);
81 970 100       245656 return ( blessed $amount ) ? $amount->bstr : $amount;
82             }
83             else {
84 10         359 return 0; # 0 for VBL > vbl_max
85             }
86             }
87              
88             sub _tax_deduction_formula {
89 970     970   1737 my ( $self, $vbl, $base_deduction ) = @_;
90 970         12621 my $amount = $base_deduction * ( 1 - ( $vbl - $self->f_min ) / $self->f_max );
91 970         32000 return $self->_round_to_tens($amount);
92             }
93              
94             sub _round_to_int {
95 1353     1353   8417 my ( $self, $amount ) = @_;
96 1353         4487 return int( $amount + 0.5 * ( $amount <=> 0 ) );
97             }
98              
99             sub _round_to_tens {
100 978     978   5563 my ( $self, $para_amount ) = @_;
101 978         2749 my $amount = Math::BigFloat->new($para_amount);
102              
103 978 100       162804 return 0 if $amount == 0;
104              
105 967         158481 my $afloor = $amount->copy()->bfloor();
106 967         74491 my $amodulo = $afloor->copy()->bmod( $self->ten );
107              
108 967 100 100     255765 return $amount if $amount->is_int && $amodulo == 0;
109 752         5992 return $afloor->bsub($amodulo)->badd( $self->ten );
110             }
111              
112             sub _amount_for_2018 {
113 351     351   451 my $self = shift;
114 351         6798 my $table = Business::RO::TaxDeduction::Table->new(
115             year => $self->year,
116             persons => $self->persons,
117             vbl => $self->vbl,
118             );
119 351         17477 return $table->deduction;
120             }
121              
122             1;
123              
124             __END__