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;
53 return Koha::Item->_new_from_dbic( $rs );
58 $payment_accountline->void();
65 # Make sure it is a payment we are voiding
66 return unless $self->amount < 0;
69 Koha::Account::Offsets->search(
70 { credit_id => $self->id, amount => { '<' => 0 } } );
72 $self->_result->result_source->schema->txn_do(
74 foreach my $account_offset (@account_offsets) {
76 Koha::Account::Lines->find( $account_offset->debit_id );
78 next unless $fee_paid;
80 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
81 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
82 $fee_paid->amountoutstanding($new_amount);
85 Koha::Account::Offset->new(
87 credit_id => $self->id,
88 debit_id => $fee_paid->id,
89 amount => $amount_paid,
90 type => 'Void Payment',
95 if ( C4::Context->preference("FinesLog") ) {
98 $self->borrowernumber,
101 action => 'void_payment',
102 borrowernumber => $self->borrowernumber,
103 amount => $self->amount,
104 amountoutstanding => $self->amountoutstanding,
105 description => $self->description,
106 accounttype => $self->accounttype,
107 payment_type => $self->payment_type,
109 itemnumber => $self->itemnumber,
110 manager_id => $self->manager_id,
112 [ map { $_->unblessed } @account_offsets ],
120 accounttype => 'VOID',
121 amountoutstanding => 0,
133 my $debits = $account->outstanding_debits;
134 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
136 Applies the credit to a given debits set.
138 =head4 arguments hashref
142 =item debits - Koha::Account::Lines object set of debits
144 =item offset_type (optional) - a string indicating the offset type (valid values are those from
145 the 'account_offset_types' table)
152 my ( $self, $params ) = @_;
154 my $debits = $params->{debits};
155 my $offset_type = $params->{offset_type} // 'Credit Applied';
157 unless ( $self->is_credit ) {
158 Koha::Exceptions::Account::IsNotCredit->throw(
159 error => 'Account line ' . $self->id . ' is not a credit'
163 my $available_credit = $self->amountoutstanding * -1;
165 unless ( $available_credit > 0 ) {
166 Koha::Exceptions::Account::NoAvailableCredit->throw(
167 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
171 my $schema = Koha::Database->new->schema;
173 $schema->txn_do( sub {
174 while ( my $debit = $debits->next ) {
176 unless ( $debit->is_debit ) {
177 Koha::Exceptions::Account::IsNotDebit->throw(
178 error => 'Account line ' . $debit->id . 'is not a debit'
181 my $amount_to_cancel;
182 my $owed = $debit->amountoutstanding;
184 if ( $available_credit >= $owed ) {
185 $amount_to_cancel = $owed;
187 else { # $available_credit < $debit->amountoutstanding
188 $amount_to_cancel = $available_credit;
191 # record the account offset
192 Koha::Account::Offset->new(
193 { credit_id => $self->id,
194 debit_id => $debit->id,
195 amount => $amount_to_cancel * -1,
196 type => $offset_type,
200 $available_credit -= $amount_to_cancel;
202 $self->amountoutstanding( $available_credit * -1 )->store;
203 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
207 return $available_credit;
212 This method allows updating a debit or credit on a patron's account
214 $account_line->adjust(
217 type => $update_type,
221 $update_type can be any of:
224 Authors Note: The intention here is that this method is only used
225 to adjust accountlines where the final amount is not yet known/fixed.
226 Incrementing fines are the only existing case at the time of writing,
227 all other forms of 'adjustment' should be recorded as distinct credits
228 or debits and applied, via an offset, to the corresponding debit or credit.
233 my ( $self, $params ) = @_;
235 my $amount = $params->{amount};
236 my $update_type = $params->{type};
238 unless ( exists($Koha::Account::Line::offset_type->{$update_type}) ) {
239 Koha::Exceptions::Account::UnrecognisedType->throw(
240 error => 'Update type not recognised'
244 my $account_type = $self->accounttype;
245 unless ( $Koha::Account::Line::allowed_update->{$update_type} eq $account_type ) {
246 Koha::Exceptions::Account::UnrecognisedType->throw(
247 error => 'Update type not allowed on this accounttype'
251 my $schema = Koha::Database->new->schema;
256 my $amount_before = $self->amount;
257 my $amount_outstanding_before = $self->amountoutstanding;
258 my $difference = $amount - $amount_before;
259 my $new_outstanding = $amount_outstanding_before + $difference;
261 # Catch cases that require patron refunds
262 if ( $new_outstanding < 0 ) {
264 Koha::Patrons->find( $self->borrowernumber )->account;
265 my $credit = $account->add_credit(
267 amount => $new_outstanding * -1,
268 description => 'Overpayment refund',
270 ( $update_type eq 'fine_increment' ? ( item_id => $self->itemnumber ) : ()),
273 $new_outstanding = 0;
276 # Update the account line
281 amountoutstanding => $new_outstanding,
282 ( $update_type eq 'fine_increment' ? ( lastincrement => $difference ) : ()),
286 # Record the account offset
287 my $account_offset = Koha::Account::Offset->new(
289 debit_id => $self->id,
290 type => $Koha::Account::Line::offset_type->{$update_type},
291 amount => $difference
295 if ( C4::Context->preference("FinesLog") ) {
297 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
298 $self->borrowernumber,
300 { action => $update_type,
301 borrowernumber => $self->borrowernumber,
302 accountno => $self->accountno,
304 description => undef,
305 amountoutstanding => $new_outstanding,
306 accounttype => $self->accounttype,
308 itemnumber => $self->itemnumber,
312 ) if ( $update_type eq 'fine_increment' );
322 my $bool = $line->is_credit;
329 return ( $self->amount < 0 );
334 my $bool = $line->is_debit;
341 return !$self->is_credit;
344 =head2 Internal methods
353 return 'Accountline';
364 our $offset_type = { 'fine_increment' => 'Fine Update', };
366 =head3 $allowed_update
370 our $allowed_update = { 'fine_increment' => 'FU', };
374 Kyle M Hall <kyle@bywatersolutions.com >
375 Tomás Cohen Arazi <tomascohen@theke.io>
376 Martin Renvoize <martin.renvoize@ptfs-europe.com>