line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Business::RO::TaxDeduction; |
2
|
|
|
|
|
|
|
$Business::RO::TaxDeduction::VERSION = '0.011'; |
3
|
|
|
|
|
|
|
# ABSTRACT: Romanian salary tax deduction calculator |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
170936
|
use 5.010001; |
|
2
|
|
|
|
|
7
|
|
6
|
2
|
|
|
2
|
|
766
|
use utf8; |
|
2
|
|
|
|
|
22
|
|
|
2
|
|
|
|
|
8
|
|
7
|
2
|
|
|
2
|
|
626
|
use Moo; |
|
2
|
|
|
|
|
16286
|
|
|
2
|
|
|
|
|
12
|
|
8
|
2
|
|
|
2
|
|
2680
|
use MooX::HandlesVia; |
|
2
|
|
|
|
|
13821
|
|
|
2
|
|
|
|
|
11
|
|
9
|
2
|
|
|
2
|
|
1628
|
use Math::BigFloat; |
|
2
|
|
|
|
|
79986
|
|
|
2
|
|
|
|
|
13
|
|
10
|
2
|
|
|
2
|
|
35618
|
use Scalar::Util qw(blessed); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
173
|
|
11
|
2
|
|
|
|
|
23
|
use Business::RO::TaxDeduction::Types qw( |
12
|
|
|
|
|
|
|
Int |
13
|
|
|
|
|
|
|
MathBigFloat |
14
|
2
|
|
|
2
|
|
759
|
); |
|
2
|
|
|
|
|
8
|
|
15
|
2
|
|
|
2
|
|
2165
|
use Business::RO::TaxDeduction::Amount; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
73
|
|
16
|
2
|
|
|
2
|
|
681
|
use Business::RO::TaxDeduction::Ranges; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
950
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has 'vbl' => ( |
19
|
|
|
|
|
|
|
is => 'ro', |
20
|
|
|
|
|
|
|
isa => Int, |
21
|
|
|
|
|
|
|
required => 1, |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has 'year' => ( |
25
|
|
|
|
|
|
|
is => 'ro', |
26
|
|
|
|
|
|
|
isa => Int, |
27
|
|
|
|
|
|
|
default => sub { 2016 }, |
28
|
|
|
|
|
|
|
); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has 'persons' => ( |
31
|
|
|
|
|
|
|
is => 'ro', |
32
|
|
|
|
|
|
|
isa => Int, |
33
|
|
|
|
|
|
|
default => sub { 0 }, |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has 'deduction' => ( |
37
|
|
|
|
|
|
|
is => 'ro', |
38
|
|
|
|
|
|
|
lazy => 1, |
39
|
|
|
|
|
|
|
default => sub { |
40
|
|
|
|
|
|
|
my $self = shift; |
41
|
|
|
|
|
|
|
return Business::RO::TaxDeduction::Amount->new( |
42
|
|
|
|
|
|
|
year => $self->year, |
43
|
|
|
|
|
|
|
persons => $self->persons, |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
}, |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
has 'ranges' => ( |
49
|
|
|
|
|
|
|
is => 'ro', |
50
|
|
|
|
|
|
|
lazy => 1, |
51
|
|
|
|
|
|
|
default => sub { |
52
|
|
|
|
|
|
|
my $self = shift; |
53
|
|
|
|
|
|
|
return Business::RO::TaxDeduction::Ranges->new( |
54
|
|
|
|
|
|
|
year => $self->year, |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
}, |
57
|
|
|
|
|
|
|
handles => [ qw( vbl_min vbl_max f_min f_max ) ], |
58
|
|
|
|
|
|
|
); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
has 'ten' => ( |
61
|
|
|
|
|
|
|
is => 'ro', |
62
|
|
|
|
|
|
|
isa => MathBigFloat, |
63
|
|
|
|
|
|
|
default => sub { |
64
|
|
|
|
|
|
|
return Math::BigFloat->new(10); |
65
|
|
|
|
|
|
|
}, |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub tax_deduction { |
69
|
991
|
|
|
991
|
1
|
477173
|
my $self = shift; |
70
|
991
|
|
|
|
|
2834
|
my $vbl = $self->_round_to_int( $self->vbl ); |
71
|
991
|
|
|
|
|
20207
|
my $amount = $self->deduction->amount; |
72
|
991
|
100
|
66
|
|
|
131157
|
if ( $vbl <= $self->vbl_min ) { |
|
|
100
|
|
|
|
|
|
73
|
11
|
|
|
|
|
488
|
return $amount; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
elsif ( ( $vbl > $self->vbl_min ) && ( $vbl <= $self->vbl_max ) ) { |
76
|
970
|
|
|
|
|
35505
|
$amount = $self->_tax_deduction_formula($vbl, $amount); |
77
|
970
|
100
|
|
|
|
267897
|
return ( blessed $amount ) ? $amount->bstr : $amount; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
else { |
80
|
10
|
|
|
|
|
400
|
return 0; # 0 for VBL > vbl_max |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub _tax_deduction_formula { |
85
|
970
|
|
|
970
|
|
1907
|
my ( $self, $vbl, $base_deduction ) = @_; |
86
|
970
|
|
|
|
|
13563
|
my $amount = $base_deduction * ( 1 - ( $vbl - $self->f_min ) / $self->f_max ); |
87
|
970
|
|
|
|
|
34449
|
return $self->_round_to_tens($amount); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub _round_to_int { |
91
|
1003
|
|
|
1003
|
|
8865
|
my ( $self, $amount ) = @_; |
92
|
1003
|
|
|
|
|
3826
|
return int( $amount + 0.5 * ( $amount <=> 0 ) ); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub _round_to_tens { |
96
|
978
|
|
|
978
|
|
6071
|
my ( $self, $para_amount ) = @_; |
97
|
978
|
|
|
|
|
2942
|
my $amount = Math::BigFloat->new($para_amount); |
98
|
|
|
|
|
|
|
|
99
|
978
|
100
|
|
|
|
177306
|
return 0 if $amount == 0; |
100
|
|
|
|
|
|
|
|
101
|
967
|
|
|
|
|
171914
|
my $afloor = $amount->copy()->bfloor(); |
102
|
967
|
|
|
|
|
82861
|
my $amodulo = $afloor->copy()->bmod( $self->ten ); |
103
|
|
|
|
|
|
|
|
104
|
967
|
100
|
100
|
|
|
276905
|
return $amount if $amount->is_int && $amodulo == 0; |
105
|
752
|
|
|
|
|
7004
|
return $afloor->bsub($amodulo)->badd( $self->ten ); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
1; |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
__END__ |