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::Offsets;
27 use Koha::Exceptions::Account;
30 use base qw(Koha::Object);
36 Koha::Account::Line - Koha accountline Object class
46 Return the item linked to this account line if exists
52 my $rs = $self->_result->itemnumber;
54 return Koha::Item->_new_from_dbic( $rs );
59 Return the checkout linked to this account line if exists
65 return unless $self->issue_id ;
67 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
68 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
69 return $self->{_checkout};
74 $payment_accountline->void();
76 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
77 created by the application of this credit upon any debits and mark the credit
78 as 'void' by updating it's status to "VOID".
85 # Make sure it is a payment we are voiding
86 return unless $self->amount < 0;
89 Koha::Account::Offsets->search(
90 { credit_id => $self->id, amount => { '<' => 0 } } );
92 $self->_result->result_source->schema->txn_do(
94 foreach my $account_offset (@account_offsets) {
96 Koha::Account::Lines->find( $account_offset->debit_id );
98 next unless $fee_paid;
100 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
101 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
102 $fee_paid->amountoutstanding($new_amount);
105 Koha::Account::Offset->new(
107 credit_id => $self->id,
108 debit_id => $fee_paid->id,
109 amount => $amount_paid,
110 type => 'Void Payment',
115 if ( C4::Context->preference("FinesLog") ) {
118 $self->borrowernumber,
121 action => 'void_payment',
122 borrowernumber => $self->borrowernumber,
123 amount => $self->amount,
124 amountoutstanding => $self->amountoutstanding,
125 description => $self->description,
126 accounttype => $self->accounttype,
127 payment_type => $self->payment_type,
129 itemnumber => $self->itemnumber,
130 manager_id => $self->manager_id,
132 [ map { $_->unblessed } @account_offsets ],
141 amountoutstanding => 0,
153 my $debits = $account->outstanding_debits;
154 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
156 Applies the credit to a given debits set.
158 =head4 arguments hashref
162 =item debits - Koha::Account::Lines object set of debits
164 =item offset_type (optional) - a string indicating the offset type (valid values are those from
165 the 'account_offset_types' table)
172 my ( $self, $params ) = @_;
174 my $debits = $params->{debits};
175 my $offset_type = $params->{offset_type} // 'Credit Applied';
177 unless ( $self->is_credit ) {
178 Koha::Exceptions::Account::IsNotCredit->throw(
179 error => 'Account line ' . $self->id . ' is not a credit'
183 my $available_credit = $self->amountoutstanding * -1;
185 unless ( $available_credit > 0 ) {
186 Koha::Exceptions::Account::NoAvailableCredit->throw(
187 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
191 my $schema = Koha::Database->new->schema;
193 $schema->txn_do( sub {
194 while ( my $debit = $debits->next ) {
196 unless ( $debit->is_debit ) {
197 Koha::Exceptions::Account::IsNotDebit->throw(
198 error => 'Account line ' . $debit->id . 'is not a debit'
201 my $amount_to_cancel;
202 my $owed = $debit->amountoutstanding;
204 if ( $available_credit >= $owed ) {
205 $amount_to_cancel = $owed;
207 else { # $available_credit < $debit->amountoutstanding
208 $amount_to_cancel = $available_credit;
211 # record the account offset
212 Koha::Account::Offset->new(
213 { credit_id => $self->id,
214 debit_id => $debit->id,
215 amount => $amount_to_cancel * -1,
216 type => $offset_type,
220 $available_credit -= $amount_to_cancel;
222 $self->amountoutstanding( $available_credit * -1 )->store;
223 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
225 # Same logic exists in Koha::Account::pay
226 if ( $debit->amountoutstanding == 0
227 && $debit->itemnumber
228 && $debit->accounttype
229 && $debit->accounttype eq 'L' )
231 C4::Circulation::ReturnLostItem( $self->borrowernumber, $debit->itemnumber );
237 return $available_credit;
242 This method allows updating a debit or credit on a patron's account
244 $account_line->adjust(
247 type => $update_type,
248 interface => $interface
252 $update_type can be any of:
255 Authors Note: The intention here is that this method is only used
256 to adjust accountlines where the final amount is not yet known/fixed.
257 Incrementing fines are the only existing case at the time of writing,
258 all other forms of 'adjustment' should be recorded as distinct credits
259 or debits and applied, via an offset, to the corresponding debit or credit.
264 my ( $self, $params ) = @_;
266 my $amount = $params->{amount};
267 my $update_type = $params->{type};
268 my $interface = $params->{interface};
270 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
271 Koha::Exceptions::Account::UnrecognisedType->throw(
272 error => 'Update type not recognised'
276 my $account_type = $self->accounttype;
277 my $account_status = $self->status;
281 $Koha::Account::Line::allowed_update->{$update_type}
284 && ( $Koha::Account::Line::allowed_update->{$update_type}
285 ->{$account_type} eq $account_status )
289 Koha::Exceptions::Account::UnrecognisedType->throw(
290 error => 'Update type not allowed on this accounttype' );
293 my $schema = Koha::Database->new->schema;
298 my $amount_before = $self->amount;
299 my $amount_outstanding_before = $self->amountoutstanding;
300 my $difference = $amount - $amount_before;
301 my $new_outstanding = $amount_outstanding_before + $difference;
303 my $offset_type = $account_type;
304 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
306 # Catch cases that require patron refunds
307 if ( $new_outstanding < 0 ) {
309 Koha::Patrons->find( $self->borrowernumber )->account;
310 my $credit = $account->add_credit(
312 amount => $new_outstanding * -1,
313 description => 'Overpayment refund',
315 interface => $interface,
316 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
319 $new_outstanding = 0;
322 # Update the account line
327 amountoutstanding => $new_outstanding,
331 # Record the account offset
332 my $account_offset = Koha::Account::Offset->new(
334 debit_id => $self->id,
335 type => $offset_type,
336 amount => $difference
340 if ( C4::Context->preference("FinesLog") ) {
342 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
343 $self->borrowernumber,
345 { action => $update_type,
346 borrowernumber => $self->borrowernumber,
348 description => undef,
349 amountoutstanding => $new_outstanding,
350 accounttype => $self->accounttype,
352 itemnumber => $self->itemnumber,
356 ) if ( $update_type eq 'overdue_update' );
366 my $bool = $line->is_credit;
373 return ( $self->amount < 0 );
378 my $bool = $line->is_debit;
385 return !$self->is_credit;
388 =head2 Internal methods
397 return 'Accountline';
404 =head3 $allowed_update
408 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
412 Kyle M Hall <kyle@bywatersolutions.com >
413 Tomás Cohen Arazi <tomascohen@theke.io>
414 Martin Renvoize <martin.renvoize@ptfs-europe.com>