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 $payment_accountline->void();
66 # Make sure it is a payment we are voiding
67 return unless $self->amount < 0;
70 Koha::Account::Offsets->search(
71 { credit_id => $self->id, amount => { '<' => 0 } } );
73 $self->_result->result_source->schema->txn_do(
75 foreach my $account_offset (@account_offsets) {
77 Koha::Account::Lines->find( $account_offset->debit_id );
79 next unless $fee_paid;
81 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
82 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
83 $fee_paid->amountoutstanding($new_amount);
86 Koha::Account::Offset->new(
88 credit_id => $self->id,
89 debit_id => $fee_paid->id,
90 amount => $amount_paid,
91 type => 'Void Payment',
96 if ( C4::Context->preference("FinesLog") ) {
99 $self->borrowernumber,
102 action => 'void_payment',
103 borrowernumber => $self->borrowernumber,
104 amount => $self->amount,
105 amountoutstanding => $self->amountoutstanding,
106 description => $self->description,
107 accounttype => $self->accounttype,
108 payment_type => $self->payment_type,
110 itemnumber => $self->itemnumber,
111 manager_id => $self->manager_id,
113 [ map { $_->unblessed } @account_offsets ],
121 accounttype => 'VOID',
122 amountoutstanding => 0,
134 my $debits = $account->outstanding_debits;
135 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
137 Applies the credit to a given debits set.
139 =head4 arguments hashref
143 =item debits - Koha::Account::Lines object set of debits
145 =item offset_type (optional) - a string indicating the offset type (valid values are those from
146 the 'account_offset_types' table)
153 my ( $self, $params ) = @_;
155 my $debits = $params->{debits};
156 my $offset_type = $params->{offset_type} // 'Credit Applied';
158 unless ( $self->is_credit ) {
159 Koha::Exceptions::Account::IsNotCredit->throw(
160 error => 'Account line ' . $self->id . ' is not a credit'
164 my $available_credit = $self->amountoutstanding * -1;
166 unless ( $available_credit > 0 ) {
167 Koha::Exceptions::Account::NoAvailableCredit->throw(
168 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
172 my $schema = Koha::Database->new->schema;
174 $schema->txn_do( sub {
175 while ( my $debit = $debits->next ) {
177 unless ( $debit->is_debit ) {
178 Koha::Exceptions::Account::IsNotDebit->throw(
179 error => 'Account line ' . $debit->id . 'is not a debit'
182 my $amount_to_cancel;
183 my $owed = $debit->amountoutstanding;
185 if ( $available_credit >= $owed ) {
186 $amount_to_cancel = $owed;
188 else { # $available_credit < $debit->amountoutstanding
189 $amount_to_cancel = $available_credit;
192 # record the account offset
193 Koha::Account::Offset->new(
194 { credit_id => $self->id,
195 debit_id => $debit->id,
196 amount => $amount_to_cancel * -1,
197 type => $offset_type,
201 $available_credit -= $amount_to_cancel;
203 $self->amountoutstanding( $available_credit * -1 )->store;
204 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
208 return $available_credit;
213 This method allows updating a debit or credit on a patron's account
215 $account_line->adjust(
218 type => $update_type,
222 $update_type can be any of:
225 Authors Note: The intention here is that this method is only used
226 to adjust accountlines where the final amount is not yet known/fixed.
227 Incrementing fines are the only existing case at the time of writing,
228 all other forms of 'adjustment' should be recorded as distinct credits
229 or debits and applied, via an offset, to the corresponding debit or credit.
234 my ( $self, $params ) = @_;
236 my $amount = $params->{amount};
237 my $update_type = $params->{type};
239 unless ( exists($Koha::Account::Line::offset_type->{$update_type}) ) {
240 Koha::Exceptions::Account::UnrecognisedType->throw(
241 error => 'Update type not recognised'
245 my $account_type = $self->accounttype;
246 unless ( $Koha::Account::Line::allowed_update->{$update_type} eq $account_type ) {
247 Koha::Exceptions::Account::UnrecognisedType->throw(
248 error => 'Update type not allowed on this accounttype'
252 my $schema = Koha::Database->new->schema;
257 my $amount_before = $self->amount;
258 my $amount_outstanding_before = $self->amountoutstanding;
259 my $difference = $amount - $amount_before;
260 my $new_outstanding = $amount_outstanding_before + $difference;
262 # Catch cases that require patron refunds
263 if ( $new_outstanding < 0 ) {
265 Koha::Patrons->find( $self->borrowernumber )->account;
266 my $credit = $account->add_credit(
268 amount => $new_outstanding * -1,
269 description => 'Overpayment refund',
271 ( $update_type eq 'fine_increment' ? ( item_id => $self->itemnumber ) : ()),
274 $new_outstanding = 0;
277 # Update the account line
282 amountoutstanding => $new_outstanding,
283 ( $update_type eq 'fine_increment' ? ( lastincrement => $difference ) : ()),
287 # Record the account offset
288 my $account_offset = Koha::Account::Offset->new(
290 debit_id => $self->id,
291 type => $Koha::Account::Line::offset_type->{$update_type},
292 amount => $difference
296 if ( C4::Context->preference("FinesLog") ) {
298 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
299 $self->borrowernumber,
301 { action => $update_type,
302 borrowernumber => $self->borrowernumber,
303 accountno => $self->accountno,
305 description => undef,
306 amountoutstanding => $new_outstanding,
307 accounttype => $self->accounttype,
309 itemnumber => $self->itemnumber,
313 ) if ( $update_type eq 'fine_increment' );
323 my $bool = $line->is_credit;
330 return ( $self->amount < 0 );
335 my $bool = $line->is_debit;
342 return !$self->is_credit;
345 =head2 Internal methods
354 return 'Accountline';
365 our $offset_type = { 'fine_increment' => 'Fine Update', };
367 =head3 $allowed_update
371 our $allowed_update = { 'fine_increment' => 'FU', };
375 Kyle M Hall <kyle@bywatersolutions.com >
376 Tomás Cohen Arazi <tomascohen@theke.io>
377 Martin Renvoize <martin.renvoize@ptfs-europe.com>