Increment version for 18.11.03 release
[koha.git] / Koha / Account / Line.pm
1 package Koha::Account::Line;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 use Modern::Perl;
19
20 use Carp;
21 use Data::Dumper;
22
23 use C4::Log qw(logaction);
24
25 use Koha::Account::Offsets;
26 use Koha::Database;
27 use Koha::Exceptions::Account;
28 use Koha::Items;
29
30 use base qw(Koha::Object);
31
32 =head1 NAME
33
34 Koha::Account::Line - Koha accountline Object class
35
36 =head1 API
37
38 =head2 Class methods
39
40 =cut
41
42 =head3 item
43
44 Return the item linked to this account line if exists
45
46 =cut
47
48 sub item {
49     my ( $self ) = @_;
50     my $rs = $self->_result->itemnumber;
51     return unless $rs;
52     return Koha::Item->_new_from_dbic( $rs );
53 }
54
55 =head3 void
56
57 $payment_accountline->void();
58
59 =cut
60
61 sub void {
62     my ($self) = @_;
63
64     # Make sure it is a payment we are voiding
65     return unless $self->amount < 0;
66
67     my @account_offsets =
68       Koha::Account::Offsets->search(
69         { credit_id => $self->id, amount => { '<' => 0 }  } );
70
71     $self->_result->result_source->schema->txn_do(
72         sub {
73             foreach my $account_offset (@account_offsets) {
74                 my $fee_paid =
75                   Koha::Account::Lines->find( $account_offset->debit_id );
76
77                 next unless $fee_paid;
78
79                 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
80                 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
81                 $fee_paid->amountoutstanding($new_amount);
82                 $fee_paid->store();
83
84                 Koha::Account::Offset->new(
85                     {
86                         credit_id => $self->id,
87                         debit_id  => $fee_paid->id,
88                         amount    => $amount_paid,
89                         type      => 'Void Payment',
90                     }
91                 )->store();
92             }
93
94             if ( C4::Context->preference("FinesLog") ) {
95                 logaction(
96                     "FINES", 'VOID',
97                     $self->borrowernumber,
98                     Dumper(
99                         {
100                             action         => 'void_payment',
101                             borrowernumber => $self->borrowernumber,
102                             amount            => $self->amount,
103                             amountoutstanding => $self->amountoutstanding,
104                             description       => $self->description,
105                             accounttype       => $self->accounttype,
106                             payment_type      => $self->payment_type,
107                             note              => $self->note,
108                             itemnumber        => $self->itemnumber,
109                             manager_id        => $self->manager_id,
110                             offsets =>
111                               [ map { $_->unblessed } @account_offsets ],
112                         }
113                     )
114                 );
115             }
116
117             $self->set(
118                 {
119                     accounttype       => 'VOID',
120                     amountoutstanding => 0,
121                     amount            => 0,
122                 }
123             );
124             $self->store();
125         }
126     );
127
128 }
129
130 =head3 apply
131
132     my $debits = $account->outstanding_debits;
133     my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
134
135 Applies the credit to a given debits set.
136
137 =head4 arguments hashref
138
139 =over 4
140
141 =item debits - Koha::Account::Lines object set of debits
142
143 =item offset_type (optional) - a string indicating the offset type (valid values are those from
144 the 'account_offset_types' table)
145
146 =back
147
148 =cut
149
150 sub apply {
151     my ( $self, $params ) = @_;
152
153     my $debits      = $params->{debits};
154     my $offset_type = $params->{offset_type} // 'Credit Applied';
155
156     unless ( $self->is_credit ) {
157         Koha::Exceptions::Account::IsNotCredit->throw(
158             error => 'Account line ' . $self->id . ' is not a credit'
159         );
160     }
161
162     my $available_credit = $self->amountoutstanding * -1;
163
164     unless ( $available_credit > 0 ) {
165         Koha::Exceptions::Account::NoAvailableCredit->throw(
166             error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
167         );
168     }
169
170     my $schema = Koha::Database->new->schema;
171
172     $schema->txn_do( sub {
173         while ( my $debit = $debits->next ) {
174
175             unless ( $debit->is_debit ) {
176                 Koha::Exceptions::Account::IsNotDebit->throw(
177                     error => 'Account line ' . $debit->id . 'is not a debit'
178                 );
179             }
180             my $amount_to_cancel;
181             my $owed = $debit->amountoutstanding;
182
183             if ( $available_credit >= $owed ) {
184                 $amount_to_cancel = $owed;
185             }
186             else {    # $available_credit < $debit->amountoutstanding
187                 $amount_to_cancel = $available_credit;
188             }
189
190             # record the account offset
191             Koha::Account::Offset->new(
192                 {   credit_id => $self->id,
193                     debit_id  => $debit->id,
194                     amount    => $amount_to_cancel * -1,
195                     type      => $offset_type,
196                 }
197             )->store();
198
199             $available_credit -= $amount_to_cancel;
200
201             $self->amountoutstanding( $available_credit * -1 )->store;
202             $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
203         }
204     });
205
206     return $available_credit;
207 }
208
209 =head3 is_credit
210
211     my $bool = $line->is_credit;
212
213 =cut
214
215 sub is_credit {
216     my ($self) = @_;
217
218     return ( $self->amount < 0 );
219 }
220
221 =head3 is_debit
222
223     my $bool = $line->is_debit;
224
225 =cut
226
227 sub is_debit {
228     my ($self) = @_;
229
230     return !$self->is_credit;
231 }
232
233 =head2 Internal methods
234
235 =cut
236
237 =head3 _type
238
239 =cut
240
241 sub _type {
242     return 'Accountline';
243 }
244
245 1;