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);
34 Koha::Account::Line - Koha accountline Object class
44 Return the item linked to this account line if exists
50 my $rs = $self->_result->itemnumber;
51 return Koha::Item->_new_from_dbic( $rs );
56 $payment_accountline->void();
63 # Make sure it is a payment we are voiding
64 return unless $self->amount < 0;
67 Koha::Account::Offsets->search(
68 { credit_id => $self->id, amount => { '<' => 0 } } );
70 $self->_result->result_source->schema->txn_do(
72 foreach my $account_offset (@account_offsets) {
74 Koha::Account::Lines->find( $account_offset->debit_id );
76 next unless $fee_paid;
78 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
79 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
80 $fee_paid->amountoutstanding($new_amount);
83 Koha::Account::Offset->new(
85 credit_id => $self->id,
86 debit_id => $fee_paid->id,
87 amount => $amount_paid,
88 type => 'Void Payment',
93 if ( C4::Context->preference("FinesLog") ) {
96 $self->borrowernumber,
99 action => 'void_payment',
100 borrowernumber => $self->borrowernumber,
101 amount => $self->amount,
102 amountoutstanding => $self->amountoutstanding,
103 description => $self->description,
104 accounttype => $self->accounttype,
105 payment_type => $self->payment_type,
107 itemnumber => $self->itemnumber,
108 manager_id => $self->manager_id,
110 [ map { $_->unblessed } @account_offsets ],
118 accounttype => 'VOID',
119 amountoutstanding => 0,
131 my $debits = $account->outstanding_debits;
132 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
134 Applies the credit to a given debits set.
136 =head4 arguments hashref
140 =item debits - Koha::Account::Lines object set of debits
142 =item offset_type (optional) - a string indicating the offset type (valid values are those from
143 the 'account_offset_types' table)
150 my ( $self, $params ) = @_;
152 my $debits = $params->{debits};
153 my $offset_type = $params->{offset_type} // 'Credit Applied';
155 unless ( $self->is_credit ) {
156 Koha::Exceptions::Account::IsNotCredit->throw(
157 error => 'Account line ' . $self->id . ' is not a credit'
161 my $available_credit = $self->amountoutstanding * -1;
163 unless ( $available_credit > 0 ) {
164 Koha::Exceptions::Account::NoAvailableCredit->throw(
165 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
169 my $schema = Koha::Database->new->schema;
171 $schema->txn_do( sub {
172 while ( my $debit = $debits->next ) {
174 unless ( $debit->is_debit ) {
175 Koha::Exceptions::Account::IsNotDebit->throw(
176 error => 'Account line ' . $debit->id . 'is not a debit'
179 my $amount_to_cancel;
180 my $owed = $debit->amountoutstanding;
182 if ( $available_credit >= $owed ) {
183 $amount_to_cancel = $owed;
185 else { # $available_credit < $debit->amountoutstanding
186 $amount_to_cancel = $available_credit;
189 # record the account offset
190 Koha::Account::Offset->new(
191 { credit_id => $self->id,
192 debit_id => $debit->id,
193 amount => $amount_to_cancel * -1,
194 type => $offset_type,
198 $available_credit -= $amount_to_cancel;
200 $self->amountoutstanding( $available_credit * -1 )->store;
201 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
205 return $available_credit;
210 This method allows updating a debit or credit on a patron's account
212 $account_line->adjust(
215 type => $update_type,
219 $update_type can be any of:
222 Authors Note: The intention here is that this method is only used
223 to adjust accountlines where the final amount is not yet known/fixed.
224 Incrementing fines are the only existing case at the time of writing,
225 all other forms of 'adjustment' should be recorded as distinct credits
226 or debits and applied, via an offset, to the corresponding debit or credit.
231 my ( $self, $params ) = @_;
233 my $amount = $params->{amount};
234 my $update_type = $params->{type};
236 unless ( exists($Koha::Account::Line::offset_type->{$update_type}) ) {
237 Koha::Exceptions::Account::UnrecognisedType->throw(
238 error => 'Update type not recognised'
242 my $account_type = $self->accounttype;
243 unless ( $Koha::Account::Line::allowed_update->{$update_type} eq $account_type ) {
244 Koha::Exceptions::Account::UnrecognisedType->throw(
245 error => 'Update type not allowed on this accounttype'
249 my $schema = Koha::Database->new->schema;
254 my $amount_before = $self->amount;
255 my $amount_outstanding_before = $self->amountoutstanding;
256 my $difference = $amount - $amount_before;
257 my $new_outstanding = $amount_outstanding_before + $difference;
259 # Catch cases that require patron refunds
260 if ( $new_outstanding < 0 ) {
262 Koha::Patrons->find( $self->borrowernumber )->account;
263 my $credit = $account->add_credit(
265 amount => $new_outstanding * -1,
266 description => 'Overpayment refund',
268 ( $update_type eq 'fine_increment' ? ( item_id => $self->itemnumber ) : ()),
271 $new_outstanding = 0;
274 # Update the account line
279 amountoutstanding => $new_outstanding,
280 ( $update_type eq 'fine_increment' ? ( lastincrement => $difference ) : ()),
284 # Record the account offset
285 my $account_offset = Koha::Account::Offset->new(
287 debit_id => $self->id,
288 type => $Koha::Account::Line::offset_type->{$update_type},
289 amount => $difference
293 if ( C4::Context->preference("FinesLog") ) {
295 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
296 $self->borrowernumber,
298 { action => $update_type,
299 borrowernumber => $self->borrowernumber,
300 accountno => $self->accountno,
302 description => undef,
303 amountoutstanding => $new_outstanding,
304 accounttype => $self->accounttype,
306 itemnumber => $self->itemnumber,
310 ) if ( $update_type eq 'fine_increment' );
320 my $bool = $line->is_credit;
327 return ( $self->amount < 0 );
332 my $bool = $line->is_debit;
339 return !$self->is_credit;
342 =head2 Internal methods
351 return 'Accountline';
362 our $offset_type = { 'fine_increment' => 'Fine Update', };
364 =head3 $allowed_update
368 our $allowed_update = { 'fine_increment' => 'FU', };
372 Kyle M Hall <kyle@bywatersolutions.com >
373 Tomás Cohen Arazi <tomascohen@theke.io>
374 Martin Renvoize <martin.renvoize@ptfs-europe.com>