Bug 19074: Fix category display in Batch patron modification.
[koha.git] / Koha / Account.pm
1 package Koha::Account;
2
3 # Copyright 2016 ByWater Solutions
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Carp;
23 use Data::Dumper;
24
25 use C4::Log qw( logaction );
26 use C4::Stats qw( UpdateStats );
27
28 use Koha::Account::Line;
29 use Koha::Account::Lines;
30 use Koha::DateUtils qw( dt_from_string );
31
32 =head1 NAME
33
34 Koha::Accounts - Module for managing payments and fees for patrons
35
36 =cut
37
38 sub new {
39     my ( $class, $params ) = @_;
40
41     Carp::croak("No patron id passed in!") unless $params->{patron_id};
42
43     return bless( $params, $class );
44 }
45
46 =head2 pay
47
48 This method allows payments to be made against fees/fines
49
50 Koha::Account->new( { patron_id => $borrowernumber } )->pay(
51     {
52         amount     => $amount,
53         sip        => $sipmode,
54         note       => $note,
55         library_id => $branchcode,
56         lines      => $lines, # Arrayref of Koha::Account::Line objects to pay
57     }
58 );
59
60 =cut
61
62 sub pay {
63     my ( $self, $params ) = @_;
64
65     my $amount          = $params->{amount};
66     my $sip             = $params->{sip};
67     my $note            = $params->{note} || q{};
68     my $library_id      = $params->{library_id};
69     my $lines           = $params->{lines};
70     my $type            = $params->{type} || 'payment';
71
72     my $userenv = C4::Context->userenv;
73
74     # We should remove accountno, it is no longer needed
75     my $last = Koha::Account::Lines->search(
76         {
77             borrowernumber => $self->{patron_id}
78         },
79         {
80             order_by => 'accountno'
81         }
82     )->next();
83     my $accountno = $last ? $last->accountno + 1 : 1;
84
85     my $manager_id = $userenv ? $userenv->{number} : 0;
86
87     my @fines_paid; # List of account lines paid on with this payment
88
89     my $balance_remaining = $amount; # Set it now so we can adjust the amount if necessary
90     $balance_remaining ||= 0;
91
92     # We were passed a specific line to pay
93     foreach my $fine ( @$lines ) {
94         my $amount_to_pay =
95             $fine->amountoutstanding > $balance_remaining
96           ? $balance_remaining
97           : $fine->amountoutstanding;
98
99         my $old_amountoutstanding = $fine->amountoutstanding;
100         my $new_amountoutstanding = $old_amountoutstanding - $amount_to_pay;
101         $fine->amountoutstanding($new_amountoutstanding)->store();
102         $balance_remaining = $balance_remaining - $amount_to_pay;
103
104         if ( $fine->itemnumber && $fine->accounttype && ( $fine->accounttype eq 'Rep' || $fine->accounttype eq 'L' ) )
105         {
106             C4::Circulation::ReturnLostItem( $self->{patron_id}, $fine->itemnumber );
107         }
108
109         if ( C4::Context->preference("FinesLog") ) {
110             logaction(
111                 "FINES", 'MODIFY',
112                 $self->{patron_id},
113                 Dumper(
114                     {
115                         action                => 'fee_payment',
116                         borrowernumber        => $fine->borrowernumber,
117                         old_amountoutstanding => $old_amountoutstanding,
118                         new_amountoutstanding => 0,
119                         amount_paid           => $old_amountoutstanding,
120                         accountlines_id       => $fine->id,
121                         accountno             => $fine->accountno,
122                         manager_id            => $manager_id,
123                         note                  => $note,
124                     }
125                 )
126             );
127             push( @fines_paid, $fine->id );
128         }
129     }
130
131     # Were not passed a specific line to pay, or the payment was for more
132     # than the what was owed on the given line. In that case pay down other
133     # lines with remaining balance.
134     my @outstanding_fines;
135     @outstanding_fines = Koha::Account::Lines->search(
136         {
137             borrowernumber    => $self->{patron_id},
138             amountoutstanding => { '>' => 0 },
139         }
140     ) if $balance_remaining > 0;
141
142     foreach my $fine (@outstanding_fines) {
143         my $amount_to_pay =
144             $fine->amountoutstanding > $balance_remaining
145           ? $balance_remaining
146           : $fine->amountoutstanding;
147
148         my $old_amountoutstanding = $fine->amountoutstanding;
149         $fine->amountoutstanding( $old_amountoutstanding - $amount_to_pay );
150         $fine->store();
151
152         if ( C4::Context->preference("FinesLog") ) {
153             logaction(
154                 "FINES", 'MODIFY',
155                 $self->{patron_id},
156                 Dumper(
157                     {
158                         action                => "fee_$type",
159                         borrowernumber        => $fine->borrowernumber,
160                         old_amountoutstanding => $old_amountoutstanding,
161                         new_amountoutstanding => $fine->amountoutstanding,
162                         amount_paid           => $amount_to_pay,
163                         accountlines_id       => $fine->id,
164                         accountno             => $fine->accountno,
165                         manager_id            => $manager_id,
166                         note                  => $note,
167                     }
168                 )
169             );
170             push( @fines_paid, $fine->id );
171         }
172
173         $balance_remaining = $balance_remaining - $amount_to_pay;
174         last unless $balance_remaining > 0;
175     }
176
177     my $account_type =
178         $type eq 'writeoff' ? 'W'
179       : defined($sip)       ? "Pay$sip"
180       :                       'Pay';
181
182     my $description = $type eq 'writeoff' ? 'Writeoff' : q{};
183
184     my $payment = Koha::Account::Line->new(
185         {
186             borrowernumber    => $self->{patron_id},
187             accountno         => $accountno,
188             date              => dt_from_string(),
189             amount            => 0 - $amount,
190             description       => $description,
191             accounttype       => $account_type,
192             amountoutstanding => 0 - $balance_remaining,
193             manager_id        => $manager_id,
194             note              => $note,
195         }
196     )->store();
197
198     $library_id ||= $userenv ? $userenv->{'branch'} : undef;
199
200     UpdateStats(
201         {
202             branch         => $library_id,
203             type           => $type,
204             amount         => $amount,
205             borrowernumber => $self->{patron_id},
206             accountno      => $accountno,
207         }
208     );
209
210     if ( C4::Context->preference("FinesLog") ) {
211         logaction(
212             "FINES", 'CREATE',
213             $self->{patron_id},
214             Dumper(
215                 {
216                     action            => "create_$type",
217                     borrowernumber    => $self->{patron_id},
218                     accountno         => $accountno,
219                     amount            => 0 - $amount,
220                     amountoutstanding => 0 - $balance_remaining,
221                     accounttype       => $account_type,
222                     accountlines_paid => \@fines_paid,
223                     manager_id        => $manager_id,
224                 }
225             )
226         );
227     }
228
229     return $payment->id;
230 }
231
232 =head3 balance
233
234 my $balance = $self->balance
235
236 Return the balance (sum of amountoutstanding columns)
237
238 =cut
239
240 sub balance {
241     my ($self) = @_;
242     my $fines = Koha::Account::Lines->search(
243         {
244             borrowernumber => $self->{patron_id},
245         },
246         {
247             select => [ { sum => 'amountoutstanding' } ],
248             as => ['total_amountoutstanding'],
249         }
250     );
251     return $fines->count
252       ? $fines->next->get_column('total_amountoutstanding')
253       : 0;
254 }
255
256 1;
257
258 =head1 AUTHOR
259
260 Kyle M Hall <kyle.m.hall@gmail.com>
261
262 =cut