Bug 20750: (QA follow-up) Fix templates
[koha.git] / Koha / Account / Line.pm
blob5029c4ba34a91cdacdc4b3338639e5313ded7495
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
8 # version.
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.
18 use Modern::Perl;
20 use Carp;
21 use Data::Dumper;
23 use C4::Log qw(logaction);
25 use Koha::Account::Offsets;
26 use Koha::Database;
27 use Koha::Exceptions::Account;
28 use Koha::Items;
30 use base qw(Koha::Object);
32 =encoding utf8
34 =head1 NAME
36 Koha::Account::Line - Koha accountline Object class
38 =head1 API
40 =head2 Class methods
42 =cut
44 =head3 item
46 Return the item linked to this account line if exists
48 =cut
50 sub item {
51 my ( $self ) = @_;
52 my $rs = $self->_result->itemnumber;
53 return unless $rs;
54 return Koha::Item->_new_from_dbic( $rs );
57 =head3 checkout
59 Return the checkout linked to this account line if exists
61 =cut
63 sub checkout {
64 my ( $self ) = @_;
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};
72 =head3 void
74 $payment_accountline->void();
76 =cut
78 sub void {
79 my ($self) = @_;
81 # Make sure it is a payment we are voiding
82 return unless $self->amount < 0;
84 my @account_offsets =
85 Koha::Account::Offsets->search(
86 { credit_id => $self->id, amount => { '<' => 0 } } );
88 $self->_result->result_source->schema->txn_do(
89 sub {
90 foreach my $account_offset (@account_offsets) {
91 my $fee_paid =
92 Koha::Account::Lines->find( $account_offset->debit_id );
94 next unless $fee_paid;
96 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
97 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
98 $fee_paid->amountoutstanding($new_amount);
99 $fee_paid->store();
101 Koha::Account::Offset->new(
103 credit_id => $self->id,
104 debit_id => $fee_paid->id,
105 amount => $amount_paid,
106 type => 'Void Payment',
108 )->store();
111 if ( C4::Context->preference("FinesLog") ) {
112 logaction(
113 "FINES", 'VOID',
114 $self->borrowernumber,
115 Dumper(
117 action => 'void_payment',
118 borrowernumber => $self->borrowernumber,
119 amount => $self->amount,
120 amountoutstanding => $self->amountoutstanding,
121 description => $self->description,
122 accounttype => $self->accounttype,
123 payment_type => $self->payment_type,
124 note => $self->note,
125 itemnumber => $self->itemnumber,
126 manager_id => $self->manager_id,
127 offsets =>
128 [ map { $_->unblessed } @account_offsets ],
134 $self->set(
136 accounttype => 'VOID',
137 amountoutstanding => 0,
138 amount => 0,
141 $self->store();
147 =head3 apply
149 my $debits = $account->outstanding_debits;
150 my $outstanding_amount = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
152 Applies the credit to a given debits set.
154 =head4 arguments hashref
156 =over 4
158 =item debits - Koha::Account::Lines object set of debits
160 =item offset_type (optional) - a string indicating the offset type (valid values are those from
161 the 'account_offset_types' table)
163 =back
165 =cut
167 sub apply {
168 my ( $self, $params ) = @_;
170 my $debits = $params->{debits};
171 my $offset_type = $params->{offset_type} // 'Credit Applied';
173 unless ( $self->is_credit ) {
174 Koha::Exceptions::Account::IsNotCredit->throw(
175 error => 'Account line ' . $self->id . ' is not a credit'
179 my $available_credit = $self->amountoutstanding * -1;
181 unless ( $available_credit > 0 ) {
182 Koha::Exceptions::Account::NoAvailableCredit->throw(
183 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
187 my $schema = Koha::Database->new->schema;
189 $schema->txn_do( sub {
190 while ( my $debit = $debits->next ) {
192 unless ( $debit->is_debit ) {
193 Koha::Exceptions::Account::IsNotDebit->throw(
194 error => 'Account line ' . $debit->id . 'is not a debit'
197 my $amount_to_cancel;
198 my $owed = $debit->amountoutstanding;
200 if ( $available_credit >= $owed ) {
201 $amount_to_cancel = $owed;
203 else { # $available_credit < $debit->amountoutstanding
204 $amount_to_cancel = $available_credit;
207 # record the account offset
208 Koha::Account::Offset->new(
209 { credit_id => $self->id,
210 debit_id => $debit->id,
211 amount => $amount_to_cancel * -1,
212 type => $offset_type,
214 )->store();
216 $available_credit -= $amount_to_cancel;
218 $self->amountoutstanding( $available_credit * -1 )->store;
219 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
223 return $available_credit;
226 =head3 adjust
228 This method allows updating a debit or credit on a patron's account
230 $account_line->adjust(
232 amount => $amount,
233 type => $update_type,
237 $update_type can be any of:
238 - fine_update
240 Authors Note: The intention here is that this method is only used
241 to adjust accountlines where the final amount is not yet known/fixed.
242 Incrementing fines are the only existing case at the time of writing,
243 all other forms of 'adjustment' should be recorded as distinct credits
244 or debits and applied, via an offset, to the corresponding debit or credit.
246 =cut
248 sub adjust {
249 my ( $self, $params ) = @_;
251 my $amount = $params->{amount};
252 my $update_type = $params->{type};
254 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
255 Koha::Exceptions::Account::UnrecognisedType->throw(
256 error => 'Update type not recognised'
260 my $account_type = $self->accounttype;
261 unless ( $Koha::Account::Line::allowed_update->{$update_type} eq $account_type ) {
262 Koha::Exceptions::Account::UnrecognisedType->throw(
263 error => 'Update type not allowed on this accounttype'
267 my $schema = Koha::Database->new->schema;
269 $schema->txn_do(
270 sub {
272 my $amount_before = $self->amount;
273 my $amount_outstanding_before = $self->amountoutstanding;
274 my $difference = $amount - $amount_before;
275 my $new_outstanding = $amount_outstanding_before + $difference;
277 my $offset_type = substr( $update_type, 0, index( $update_type, '_' ) );
278 $offset_type .= ( $difference > 0 ) ? "_increase" : "_decrease";
280 # Catch cases that require patron refunds
281 if ( $new_outstanding < 0 ) {
282 my $account =
283 Koha::Patrons->find( $self->borrowernumber )->account;
284 my $credit = $account->add_credit(
286 amount => $new_outstanding * -1,
287 description => 'Overpayment refund',
288 type => 'credit',
289 ( $update_type eq 'fine_update' ? ( item_id => $self->itemnumber ) : ()),
292 $new_outstanding = 0;
295 # Update the account line
296 $self->set(
298 date => \'NOW()',
299 amount => $amount,
300 amountoutstanding => $new_outstanding,
301 ( $update_type eq 'fine_update' ? ( lastincrement => $difference ) : ()),
303 )->store();
305 # Record the account offset
306 my $account_offset = Koha::Account::Offset->new(
308 debit_id => $self->id,
309 type => $offset_type,
310 amount => $difference
312 )->store();
314 if ( C4::Context->preference("FinesLog") ) {
315 logaction(
316 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
317 $self->borrowernumber,
318 Dumper(
319 { action => $update_type,
320 borrowernumber => $self->borrowernumber,
321 accountno => $self->accountno,
322 amount => $amount,
323 description => undef,
324 amountoutstanding => $new_outstanding,
325 accounttype => $self->accounttype,
326 note => undef,
327 itemnumber => $self->itemnumber,
328 manager_id => undef,
331 ) if ( $update_type eq 'fine_update' );
336 return $self;
339 =head3 is_credit
341 my $bool = $line->is_credit;
343 =cut
345 sub is_credit {
346 my ($self) = @_;
348 return ( $self->amount < 0 );
351 =head3 is_debit
353 my $bool = $line->is_debit;
355 =cut
357 sub is_debit {
358 my ($self) = @_;
360 return !$self->is_credit;
363 =head2 Internal methods
365 =cut
367 =head3 _type
369 =cut
371 sub _type {
372 return 'Accountline';
377 =head2 Name mappings
379 =head3 $allowed_update
381 =cut
383 our $allowed_update = { 'fine_update' => 'FU', };
385 =head1 AUTHORS
387 Kyle M Hall <kyle@bywatersolutions.com >
388 Tomás Cohen Arazi <tomascohen@theke.io>
389 Martin Renvoize <martin.renvoize@ptfs-europe.com>
391 =cut