File Coverage

blib/lib/Finance/Loan/Repayment.pm
Criterion Covered Total %
statement 29 30 96.6
branch 11 12 91.6
condition 7 12 58.3
subroutine 6 6 100.0
pod 3 3 100.0
total 56 63 88.8


line stmt bran cond sub pod time code
1             package Finance::Loan::Repayment;
2 1     1   65658 use Moose;
  1         471409  
  1         8  
3              
4             # ABSTRACT: Play with loans, rates and repayment options
5             our $VERSION = '1.5';
6              
7             has loan => (
8             is => 'rw',
9             isa => 'Num',
10             required => 1,
11             );
12              
13             has rate => (
14             is => 'ro',
15             isa => 'Num',
16             required => 1,
17             );
18              
19             has duration => (
20             is => 'ro',
21             isa => 'Num',
22             );
23              
24             has principal_payment => (
25             is => 'ro',
26             isa => 'Num',
27             );
28              
29             has interest_off => (
30             is => 'ro',
31             isa => 'Num',
32             );
33              
34             has total_payment => (
35             is => 'ro',
36             isa => 'Num',
37             );
38              
39             sub BUILDARGS {
40 6     6 1 10 my $self = shift;
41 6         31 my %args = @_;
42              
43 6 100 66     34 if ($args{rate} && exists $args{duration} && !$args{total_payment}) {
      66        
44 1         5 my $monthly_rate = $args{rate} / 100 / 12;
45 1         2 my $duration = $args{duration};
46 1         10 my $a = $args{loan} * ($monthly_rate * ((1 + $monthly_rate) ** $duration));
47 1         5 my $b = ((1 + $monthly_rate) ** $duration) - 1;
48 1         3 $args{total_payment} = $a / $b;
49             }
50 6         176 return \%args;
51             }
52              
53             sub _interest_per_month {
54 10     10   16 my $loan = shift;
55 10         16 my $rate = shift;
56 10         34 return $loan * ($rate / 100 / 12);
57             }
58              
59             sub interest_per_month {
60 10     10 1 1697 my $self = shift;
61 10   66     331 return _interest_per_month(shift // $self->loan, $self->rate);
62             }
63              
64             sub principal_per_month {
65 6     6 1 1374 my $self = shift;
66 6   33     198 my $loan = shift // $self->loan;
67              
68 6         16 my $interest = $self->interest_per_month($loan);
69              
70 6 100       175 if ($self->principal_payment) {
    100          
    100          
71 2         58 return $self->_check_payment_vs_loan($self->principal_payment, $loan);
72             }
73             elsif ($self->total_payment) {
74 2 50       59 if ($self->total_payment > $interest) {
75 2         56 return $self->_check_payment_vs_loan(
76             $self->total_payment - $interest,
77             $loan
78             );
79             }
80 0         0 die "Total payment is too small to cover interest";
81             }
82             elsif ($self->interest_off) {
83 1         29 my $new_loan = (($interest - $self->interest_off) * 12)
84             / ($self->rate / 100);
85 1         4 return $self->_check_payment_vs_loan($loan - $new_loan, $loan);
86             }
87 1         3 return 0;
88             }
89              
90             sub _check_payment_vs_loan {
91 5     5   16 my ($self, $payment, $loan) = @_;
92 5 100       23 return ($payment > $loan) ? $loan : $payment;
93             }
94              
95              
96             __PACKAGE__->meta->make_immutable;
97              
98             __END__
99              
100             =pod
101              
102             =encoding UTF-8
103              
104             =head1 NAME
105              
106             Finance::Loan::Repayment - Play with loans, rates and repayment options
107              
108             =head1 VERSION
109              
110             version 1.5
111              
112             =head1 SYNOPSIS
113              
114             use Finance::Loan::Repayment;
115              
116             my $calc = Finance::Loan::Repayment->new(
117             loan => 100,
118             rate => 5,
119              
120             # The following parameters are optional
121             # Reduce interest by 1 each month
122             interest_off => 1,
123              
124             # Principal payment per month
125             principal_payment => 30,
126              
127             # Total amount to pay per month
128             total_payment => 30,
129              
130             );
131              
132             =head1 DESCRIPTION
133              
134             A module to calculate interest per month and principal payments per month
135              
136             =head1 ATTRIBUTES
137              
138             =head2 loan
139              
140             The loan amount, required.
141              
142             =head2 rate
143              
144             The interest rate of the loan, required.
145              
146             =head1 Attributes changing the way the C<principal_payment_per_month> functions works
147              
148             The following attributes will alter how the principal payment per month
149             function will work.
150              
151             =head2 principal_payment
152              
153             The amount you want to pay off your loan each month. This changes the
154             total costs per month and the interest you pay.
155              
156             =head2 interest_off
157              
158             The amount you want to pay off your interest each month. This changes the
159             total costs per month and the interest you pay. This will make your
160             additional payment steady.
161              
162             =head2 total_payment
163              
164             The amount you want to pay off each month. This will influence the interest
165             you pay and the principal payment.
166              
167             =head1 METHODS
168              
169             =head2 interest_per_month
170              
171             $calc->interest_per_month();
172             $calc->interest_per_month(1000);
173              
174             Calculates the interest amount per month on the loan. An optional loan
175             parameter can be used.
176              
177             =head2 principal_per_month()
178              
179             $calc->principal_per_month();
180             $calc->principal_per_month(1000);
181              
182             Calculates the principal payments per month based on the constructor
183             arguments. An optional loan parameter can be used.
184              
185             =head1 SEE ALSO
186              
187             =over
188              
189             =item L<Finance::Amortization>
190              
191             This does more or less the same thing as this module
192              
193             =item L<Finance::Loan>
194              
195             =item L<Finance::Loan::Private>
196              
197             =back
198              
199             =head1 AUTHOR
200              
201             Wesley Schwengle <waterkip@cpan.org>
202              
203             =head1 COPYRIGHT AND LICENSE
204              
205             This software is Copyright (c) 2017 by Wesley Schwengle.
206              
207             This is free software, licensed under:
208              
209             The MIT (X11) License
210              
211             =cut