File Coverage

blib/lib/Business/RO/TaxDeduction.pm
Criterion Covered Total %
statement 46 46 100.0
branch 10 10 100.0
condition 5 6 83.3
subroutine 13 13 100.0
pod 1 1 100.0
total 75 76 98.6


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__