1 package Koha::Account::Line;
3 # This file is part of Koha.
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
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.
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.
23 use C4::Log qw(logaction);
25 use Koha::Account::CreditType;
26 use Koha::Account::DebitType;
27 use Koha::Account::Offsets;
29 use Koha::Exceptions::Account;
32 use base qw(Koha::Object);
38 Koha::Account::Line - Koha accountline Object class
48 Return the patron linked to this account line
54 my $rs = $self->_result->borrowernumber;
56 return Koha::Patron->_new_from_dbic( $rs );
61 Return the item linked to this account line if exists
67 my $rs = $self->_result->itemnumber;
69 return Koha::Item->_new_from_dbic( $rs );
74 Return the checkout linked to this account line if exists
80 return unless $self->issue_id ;
82 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
83 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
84 return $self->{_checkout};
89 Return the credit_type linked to this account line
95 my $rs = $self->_result->credit_type_code;
97 return Koha::Account::CreditType->_new_from_dbic( $rs );
102 Return the debit_type linked to this account line
108 my $rs = $self->_result->debit_type_code;
110 return Koha::Account::DebitType->_new_from_dbic( $rs );
115 $payment_accountline->void();
117 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
118 created by the application of this credit upon any debits and mark the credit
119 as 'void' by updating it's status to "VOID".
126 # Make sure it is a payment we are voiding
127 return unless $self->amount < 0;
129 my @account_offsets =
130 Koha::Account::Offsets->search(
131 { credit_id => $self->id, amount => { '<' => 0 } } );
133 $self->_result->result_source->schema->txn_do(
135 foreach my $account_offset (@account_offsets) {
137 Koha::Account::Lines->find( $account_offset->debit_id );
139 next unless $fee_paid;
141 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
142 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
143 $fee_paid->amountoutstanding($new_amount);
146 Koha::Account::Offset->new(
148 credit_id => $self->id,
149 debit_id => $fee_paid->id,
150 amount => $amount_paid,
151 type => 'Void Payment',
156 if ( C4::Context->preference("FinesLog") ) {
159 $self->borrowernumber,
162 action => 'void_payment',
163 borrowernumber => $self->borrowernumber,
164 amount => $self->amount,
165 amountoutstanding => $self->amountoutstanding,
166 description => $self->description,
167 credit_type_code => $self->credit_type_code,
168 payment_type => $self->payment_type,
170 itemnumber => $self->itemnumber,
171 manager_id => $self->manager_id,
173 [ map { $_->unblessed } @account_offsets ],
182 amountoutstanding => 0,
194 my $debits = $account->outstanding_debits;
195 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
197 Applies the credit to a given debits array reference.
199 =head4 arguments hashref
203 =item debits - Koha::Account::Lines object set of debits
205 =item offset_type (optional) - a string indicating the offset type (valid values are those from
206 the 'account_offset_types' table)
213 my ( $self, $params ) = @_;
215 my $debits = $params->{debits};
216 my $offset_type = $params->{offset_type} // 'Credit Applied';
218 unless ( $self->is_credit ) {
219 Koha::Exceptions::Account::IsNotCredit->throw(
220 error => 'Account line ' . $self->id . ' is not a credit'
224 my $available_credit = $self->amountoutstanding * -1;
226 unless ( $available_credit > 0 ) {
227 Koha::Exceptions::Account::NoAvailableCredit->throw(
228 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
232 my $schema = Koha::Database->new->schema;
234 $schema->txn_do( sub {
235 for my $debit ( @{$debits} ) {
237 unless ( $debit->is_debit ) {
238 Koha::Exceptions::Account::IsNotDebit->throw(
239 error => 'Account line ' . $debit->id . 'is not a debit'
242 my $amount_to_cancel;
243 my $owed = $debit->amountoutstanding;
245 if ( $available_credit >= $owed ) {
246 $amount_to_cancel = $owed;
248 else { # $available_credit < $debit->amountoutstanding
249 $amount_to_cancel = $available_credit;
252 # record the account offset
253 Koha::Account::Offset->new(
254 { credit_id => $self->id,
255 debit_id => $debit->id,
256 amount => $amount_to_cancel * -1,
257 type => $offset_type,
261 $available_credit -= $amount_to_cancel;
263 $self->amountoutstanding( $available_credit * -1 )->store;
264 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
266 # Same logic exists in Koha::Account::pay
267 if ( $debit->amountoutstanding == 0
268 && $debit->itemnumber
269 && $debit->debit_type_code
270 && $debit->debit_type_code eq 'LOST' )
272 C4::Circulation::ReturnLostItem( $self->borrowernumber, $debit->itemnumber );
278 return $available_credit;
283 This method allows updating a debit or credit on a patron's account
285 $account_line->adjust(
288 type => $update_type,
289 interface => $interface
293 $update_type can be any of:
296 Authors Note: The intention here is that this method is only used
297 to adjust accountlines where the final amount is not yet known/fixed.
298 Incrementing fines are the only existing case at the time of writing,
299 all other forms of 'adjustment' should be recorded as distinct credits
300 or debits and applied, via an offset, to the corresponding debit or credit.
305 my ( $self, $params ) = @_;
307 my $amount = $params->{amount};
308 my $update_type = $params->{type};
309 my $interface = $params->{interface};
311 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
312 Koha::Exceptions::Account::UnrecognisedType->throw(
313 error => 'Update type not recognised'
317 my $debit_type_code = $self->debit_type_code;
318 my $account_status = $self->status;
322 $Koha::Account::Line::allowed_update->{$update_type}
325 && ( $Koha::Account::Line::allowed_update->{$update_type}
326 ->{$debit_type_code} eq $account_status )
330 Koha::Exceptions::Account::UnrecognisedType->throw(
331 error => 'Update type not allowed on this debit_type' );
334 my $schema = Koha::Database->new->schema;
339 my $amount_before = $self->amount;
340 my $amount_outstanding_before = $self->amountoutstanding;
341 my $difference = $amount - $amount_before;
342 my $new_outstanding = $amount_outstanding_before + $difference;
344 my $offset_type = $debit_type_code;
345 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
347 # Catch cases that require patron refunds
348 if ( $new_outstanding < 0 ) {
350 Koha::Patrons->find( $self->borrowernumber )->account;
351 my $credit = $account->add_credit(
353 amount => $new_outstanding * -1,
354 description => 'Overpayment refund',
356 interface => $interface,
357 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
360 $new_outstanding = 0;
363 # Update the account line
368 amountoutstanding => $new_outstanding,
372 # Record the account offset
373 my $account_offset = Koha::Account::Offset->new(
375 debit_id => $self->id,
376 type => $offset_type,
377 amount => $difference
381 if ( C4::Context->preference("FinesLog") ) {
383 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
384 $self->borrowernumber,
386 { action => $update_type,
387 borrowernumber => $self->borrowernumber,
389 description => undef,
390 amountoutstanding => $new_outstanding,
391 debit_type_code => $self->debit_type_code,
393 itemnumber => $self->itemnumber,
397 ) if ( $update_type eq 'overdue_update' );
407 my $bool = $line->is_credit;
414 return ( $self->amount < 0 );
419 my $bool = $line->is_debit;
426 return !$self->is_credit;
429 =head3 to_api_mapping
431 This method returns the mapping for representing a Koha::Account::Line object
438 accountlines_id => 'account_line_id',
439 credit_type_code => 'credit_type',
440 debit_type_code => 'debit_type',
441 amountoutstanding => 'amount_outstanding',
442 borrowernumber => 'patron_id',
443 branchcode => 'library_id',
444 issue_id => 'checkout_id',
445 itemnumber => 'item_id',
446 manager_id => 'user_id',
447 note => 'internal_note',
451 =head2 Internal methods
460 return 'Accountline';
467 =head3 $allowed_update
471 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
475 Kyle M Hall <kyle@bywatersolutions.com >
476 Tomás Cohen Arazi <tomascohen@theke.io>
477 Martin Renvoize <martin.renvoize@ptfs-europe.com>