a4f73bbb8d21f732e4d208e9eb25326c0b6f31d3
[koha.git] / Koha / Account.pm
1 package Koha::Account;
2
3 # Copyright 2016 ByWater Solutions
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Carp;
23 use Data::Dumper;
24 use List::MoreUtils qw( uniq );
25 use Try::Tiny;
26
27 use C4::Circulation qw( ReturnLostItem CanBookBeRenewed AddRenewal );
28 use C4::Letters;
29 use C4::Log qw( logaction );
30 use C4::Stats qw( UpdateStats );
31 use C4::Overdues qw(GetFine);
32
33 use Koha::Patrons;
34 use Koha::Account::Lines;
35 use Koha::Account::Offsets;
36 use Koha::Account::DebitTypes;
37 use Koha::DateUtils qw( dt_from_string );
38 use Koha::Exceptions;
39 use Koha::Exceptions::Account;
40
41 =head1 NAME
42
43 Koha::Accounts - Module for managing payments and fees for patrons
44
45 =cut
46
47 sub new {
48     my ( $class, $params ) = @_;
49
50     Carp::croak("No patron id passed in!") unless $params->{patron_id};
51
52     return bless( $params, $class );
53 }
54
55 =head2 pay
56
57 This method allows payments to be made against fees/fines
58
59 Koha::Account->new( { patron_id => $borrowernumber } )->pay(
60     {
61         amount      => $amount,
62         note        => $note,
63         description => $description,
64         library_id  => $branchcode,
65         lines       => $lines, # Arrayref of Koha::Account::Line objects to pay
66         credit_type => $type,  # credit_type_code code
67         offset_type => $offset_type,    # offset type code
68     }
69 );
70
71 =cut
72
73 sub pay {
74     my ( $self, $params ) = @_;
75
76     my $amount        = $params->{amount};
77     my $description   = $params->{description};
78     my $note          = $params->{note} || q{};
79     my $library_id    = $params->{library_id};
80     my $lines         = $params->{lines};
81     my $type          = $params->{type} || 'PAYMENT';
82     my $payment_type  = $params->{payment_type} || undef;
83     my $credit_type   = $params->{credit_type};
84     my $offset_type   = $params->{offset_type} || $type eq 'WRITEOFF' ? 'Writeoff' : 'Payment';
85     my $cash_register = $params->{cash_register};
86
87     my $userenv = C4::Context->userenv;
88
89     my $patron = Koha::Patrons->find( $self->{patron_id} );
90
91     my $manager_id = $userenv ? $userenv->{number} : 0;
92     my $interface = $params ? ( $params->{interface} || C4::Context->interface ) : C4::Context->interface;
93     Koha::Exceptions::Account::RegisterRequired->throw()
94       if ( C4::Context->preference("UseCashRegisters")
95         && defined($payment_type)
96         && ( $payment_type eq 'CASH' )
97         && !defined($cash_register) );
98
99     my @fines_paid; # List of account lines paid on with this payment
100     # Item numbers that have had a fine paid where the line has a accounttype
101     # of OVERDUE and a status of UNRETURNED. We might want to try and renew
102     # these items.
103     my $overdue_unreturned = {};
104
105     my $balance_remaining = $amount; # Set it now so we can adjust the amount if necessary
106     $balance_remaining ||= 0;
107
108     my @account_offsets;
109
110     # We were passed a specific line to pay
111     foreach my $fine ( @$lines ) {
112         my $amount_to_pay =
113             $fine->amountoutstanding > $balance_remaining
114           ? $balance_remaining
115           : $fine->amountoutstanding;
116
117         my $old_amountoutstanding = $fine->amountoutstanding;
118         my $new_amountoutstanding = $old_amountoutstanding - $amount_to_pay;
119         $fine->amountoutstanding($new_amountoutstanding)->store();
120         $balance_remaining = $balance_remaining - $amount_to_pay;
121
122         # If we need to make a note of the item associated with this line,
123         # in order that we can potentially renew it, do so.
124         if (
125             $new_amountoutstanding == 0 &&
126             $fine->accounttype &&
127             $fine->accounttype eq 'OVERDUE' &&
128             $fine->status &&
129             $fine->status eq 'UNRETURNED'
130         ) {
131             $overdue_unreturned->{$fine->itemnumber} = $fine;
132         }
133
134         # Same logic exists in Koha::Account::Line::apply
135         if (   $new_amountoutstanding == 0
136             && $fine->itemnumber
137             && $fine->debit_type_code
138             && ( $fine->debit_type_code eq 'LOST' ) )
139         {
140             C4::Circulation::ReturnLostItem( $self->{patron_id}, $fine->itemnumber );
141         }
142
143         my $account_offset = Koha::Account::Offset->new(
144             {
145                 debit_id => $fine->id,
146                 type     => $offset_type,
147                 amount   => $amount_to_pay * -1,
148             }
149         );
150         push( @account_offsets, $account_offset );
151
152         if ( C4::Context->preference("FinesLog") ) {
153             logaction(
154                 "FINES", 'MODIFY',
155                 $self->{patron_id},
156                 Dumper(
157                     {
158                         action                => 'fee_payment',
159                         borrowernumber        => $fine->borrowernumber,
160                         old_amountoutstanding => $old_amountoutstanding,
161                         new_amountoutstanding => 0,
162                         amount_paid           => $old_amountoutstanding,
163                         accountlines_id       => $fine->id,
164                         manager_id            => $manager_id,
165                         note                  => $note,
166                     }
167                 ),
168                 $interface
169             );
170             push( @fines_paid, $fine->id );
171         }
172     }
173
174     # Were not passed a specific line to pay, or the payment was for more
175     # than the what was owed on the given line. In that case pay down other
176     # lines with remaining balance.
177     my @outstanding_fines;
178     @outstanding_fines = $self->lines->search(
179         {
180             amountoutstanding => { '>' => 0 },
181         }
182     ) if $balance_remaining > 0;
183
184     foreach my $fine (@outstanding_fines) {
185         my $amount_to_pay =
186             $fine->amountoutstanding > $balance_remaining
187           ? $balance_remaining
188           : $fine->amountoutstanding;
189
190         my $old_amountoutstanding = $fine->amountoutstanding;
191         $fine->amountoutstanding( $old_amountoutstanding - $amount_to_pay );
192         $fine->store();
193
194         # If we need to make a note of the item associated with this line,
195         # in order that we can potentially renew it, do so.
196         if (
197             $old_amountoutstanding - $amount_to_pay == 0 &&
198             $fine->accounttype &&
199             $fine->accounttype eq 'OVERDUE' &&
200             $fine->status &&
201             $fine->status eq 'UNRETURNED'
202         ) {
203             $overdue_unreturned->{$fine->itemnumber} = $fine;
204         }
205
206         if (   $fine->amountoutstanding == 0
207             && $fine->itemnumber
208             && $fine->debit_type_code
209             && ( $fine->debit_type_code eq 'LOST' ) )
210         {
211             C4::Circulation::ReturnLostItem( $self->{patron_id}, $fine->itemnumber );
212         }
213
214         my $account_offset = Koha::Account::Offset->new(
215             {
216                 debit_id => $fine->id,
217                 type     => $offset_type,
218                 amount   => $amount_to_pay * -1,
219             }
220         );
221         push( @account_offsets, $account_offset );
222
223         if ( C4::Context->preference("FinesLog") ) {
224             logaction(
225                 "FINES", 'MODIFY',
226                 $self->{patron_id},
227                 Dumper(
228                     {
229                         action                => "fee_$type",
230                         borrowernumber        => $fine->borrowernumber,
231                         old_amountoutstanding => $old_amountoutstanding,
232                         new_amountoutstanding => $fine->amountoutstanding,
233                         amount_paid           => $amount_to_pay,
234                         accountlines_id       => $fine->id,
235                         manager_id            => $manager_id,
236                         note                  => $note,
237                     }
238                 ),
239                 $interface
240             );
241             push( @fines_paid, $fine->id );
242         }
243
244         $balance_remaining = $balance_remaining - $amount_to_pay;
245         last unless $balance_remaining > 0;
246     }
247
248     $credit_type ||=
249       $type eq 'WRITEOFF'
250       ? 'WRITEOFF'
251       : 'PAYMENT';
252
253     $description ||= $type eq 'WRITEOFF' ? 'Writeoff' : q{};
254
255     my $payment = Koha::Account::Line->new(
256         {
257             borrowernumber    => $self->{patron_id},
258             date              => dt_from_string(),
259             amount            => 0 - $amount,
260             description       => $description,
261             credit_type_code  => $credit_type,
262             payment_type      => $payment_type,
263             amountoutstanding => 0 - $balance_remaining,
264             manager_id        => $manager_id,
265             interface         => $interface,
266             branchcode        => $library_id,
267             register_id       => $cash_register,
268             note              => $note,
269         }
270     )->store();
271
272     foreach my $o ( @account_offsets ) {
273         $o->credit_id( $payment->id() );
274         $o->store();
275     }
276
277     UpdateStats(
278         {
279             branch         => $library_id,
280             type           => lc($type),
281             amount         => $amount,
282             borrowernumber => $self->{patron_id},
283         }
284     );
285
286     # If we have overdue unreturned items that have had payments made
287     # against them, check whether the balance on those items is now zero
288     # and, if the syspref is set, renew them
289     # Same logic exists in Koha::Account::Line::apply
290     if (
291         C4::Context->preference('RenewAccruingItemWhenPaid') &&
292         keys %{$overdue_unreturned}
293     ) {
294         foreach my $itemnumber (keys %{$overdue_unreturned}) {
295             # Only do something if this item has no fines left on it
296             my $fine = C4::Overdues::GetFine( $itemnumber, $self->{patron_id} );
297             next if $fine && $fine > 0;
298
299             my ( $renew_ok, $error ) =
300                 C4::Circulation::CanBookBeRenewed(
301                     $self->{patron_id}, $itemnumber
302                 );
303             if ( $renew_ok ) {
304                 C4::Circulation::AddRenewal(
305                     $self->{patron_id},
306                     $itemnumber,
307                     $library_id,
308                     undef,
309                     undef,
310                     1
311                 );
312             }
313         }
314     }
315
316     if ( C4::Context->preference("FinesLog") ) {
317         logaction(
318             "FINES", 'CREATE',
319             $self->{patron_id},
320             Dumper(
321                 {
322                     action            => "create_$type",
323                     borrowernumber    => $self->{patron_id},
324                     amount            => 0 - $amount,
325                     amountoutstanding => 0 - $balance_remaining,
326                     credit_type_code  => $credit_type,
327                     accountlines_paid => \@fines_paid,
328                     manager_id        => $manager_id,
329                 }
330             ),
331             $interface
332         );
333     }
334
335     if ( C4::Context->preference('UseEmailReceipts') ) {
336         if (
337             my $letter = C4::Letters::GetPreparedLetter(
338                 module                 => 'circulation',
339                 letter_code            => uc("ACCOUNT_$type"),
340                 message_transport_type => 'email',
341                 lang    => $patron->lang,
342                 tables => {
343                     borrowers       => $self->{patron_id},
344                     branches        => $library_id,
345                 },
346                 substitute => {
347                     credit => $payment,
348                     offsets => \@account_offsets,
349                 },
350               )
351           )
352         {
353             C4::Letters::EnqueueLetter(
354                 {
355                     letter                 => $letter,
356                     borrowernumber         => $self->{patron_id},
357                     message_transport_type => 'email',
358                 }
359             ) or warn "can't enqueue letter $letter";
360         }
361     }
362
363     return $payment->id;
364 }
365
366 =head3 add_credit
367
368 This method allows adding credits to a patron's account
369
370 my $credit_line = Koha::Account->new({ patron_id => $patron_id })->add_credit(
371     {
372         amount       => $amount,
373         description  => $description,
374         note         => $note,
375         user_id      => $user_id,
376         interface    => $interface,
377         library_id   => $library_id,
378         payment_type => $payment_type,
379         type         => $credit_type,
380         item_id      => $item_id
381     }
382 );
383
384 $credit_type can be any of:
385   - 'CREDIT'
386   - 'PAYMENT'
387   - 'FORGIVEN'
388   - 'LOST_FOUND'
389   - 'WRITEOFF'
390
391 =cut
392
393 sub add_credit {
394
395     my ( $self, $params ) = @_;
396
397     # check for mandatory params
398     my @mandatory = ( 'interface', 'amount' );
399     for my $param (@mandatory) {
400         unless ( defined( $params->{$param} ) ) {
401             Koha::Exceptions::MissingParameter->throw(
402                 error => "The $param parameter is mandatory" );
403         }
404     }
405
406     # amount should always be passed as a positive value
407     my $amount = $params->{amount} * -1;
408     unless ( $amount < 0 ) {
409         Koha::Exceptions::Account::AmountNotPositive->throw(
410             error => 'Debit amount passed is not positive' );
411     }
412
413     my $description   = $params->{description} // q{};
414     my $note          = $params->{note} // q{};
415     my $user_id       = $params->{user_id};
416     my $interface     = $params->{interface};
417     my $library_id    = $params->{library_id};
418     my $cash_register = $params->{cash_register};
419     my $payment_type  = $params->{payment_type};
420     my $credit_type   = $params->{type} || 'PAYMENT';
421     my $item_id       = $params->{item_id};
422
423     Koha::Exceptions::Account::RegisterRequired->throw()
424       if ( C4::Context->preference("UseCashRegisters")
425         && defined($payment_type)
426         && ( $payment_type eq 'CASH' )
427         && !defined($cash_register) );
428
429     my $line;
430     my $schema = Koha::Database->new->schema;
431     try {
432         $schema->txn_do(
433             sub {
434
435                 # Insert the account line
436                 $line = Koha::Account::Line->new(
437                     {
438                         borrowernumber    => $self->{patron_id},
439                         date              => \'NOW()',
440                         amount            => $amount,
441                         description       => $description,
442                         credit_type_code  => $credit_type,
443                         amountoutstanding => $amount,
444                         payment_type      => $payment_type,
445                         note              => $note,
446                         manager_id        => $user_id,
447                         interface         => $interface,
448                         branchcode        => $library_id,
449                         register_id       => $cash_register,
450                         itemnumber        => $item_id,
451                     }
452                 )->store();
453
454                 # Record the account offset
455                 my $account_offset = Koha::Account::Offset->new(
456                     {
457                         credit_id => $line->id,
458                         type   => $Koha::Account::offset_type->{$credit_type} // $Koha::Account::offset_type->{CREDIT},
459                         amount => $amount
460                     }
461                 )->store();
462
463                 UpdateStats(
464                     {
465                         branch         => $library_id,
466                         type           => lc($credit_type),
467                         amount         => $amount,
468                         borrowernumber => $self->{patron_id},
469                     }
470                 ) if grep { $credit_type eq $_ } ( 'PAYMENT', 'WRITEOFF' );
471
472                 if ( C4::Context->preference("FinesLog") ) {
473                     logaction(
474                         "FINES", 'CREATE',
475                         $self->{patron_id},
476                         Dumper(
477                             {
478                                 action            => "create_$credit_type",
479                                 borrowernumber    => $self->{patron_id},
480                                 amount            => $amount,
481                                 description       => $description,
482                                 amountoutstanding => $amount,
483                                 credit_type_code  => $credit_type,
484                                 note              => $note,
485                                 itemnumber        => $item_id,
486                                 manager_id        => $user_id,
487                                 branchcode        => $library_id,
488                             }
489                         ),
490                         $interface
491                     );
492                 }
493             }
494         );
495     }
496     catch {
497         if ( ref($_) eq 'Koha::Exceptions::Object::FKConstraint' ) {
498             if ( $_->broken_fk eq 'credit_type_code' ) {
499                 Koha::Exceptions::Account::UnrecognisedType->throw(
500                     error => 'Type of credit not recognised' );
501             }
502             else {
503                 $_->rethrow;
504             }
505         }
506     };
507
508     return $line;
509 }
510
511 =head3 add_debit
512
513 This method allows adding debits to a patron's account
514
515 my $debit_line = Koha::Account->new({ patron_id => $patron_id })->add_debit(
516     {
517         amount       => $amount,
518         description  => $description,
519         note         => $note,
520         user_id      => $user_id,
521         interface    => $interface,
522         library_id   => $library_id,
523         type         => $debit_type,
524         item_id      => $item_id,
525         issue_id     => $issue_id
526     }
527 );
528
529 $debit_type can be any of:
530   - ACCOUNT
531   - ACCOUNT_RENEW
532   - RESERVE_EXPIRED
533   - LOST
534   - sundry
535   - NEW_CARD
536   - OVERDUE
537   - PROCESSING
538   - RENT
539   - RENT_DAILY
540   - RENT_RENEW
541   - RENT_DAILY_RENEW
542   - RESERVE
543
544 =cut
545
546 sub add_debit {
547
548     my ( $self, $params ) = @_;
549
550     # check for mandatory params
551     my @mandatory = ( 'interface', 'type', 'amount' );
552     for my $param (@mandatory) {
553         unless ( defined( $params->{$param} ) ) {
554             Koha::Exceptions::MissingParameter->throw(
555                 error => "The $param parameter is mandatory" );
556         }
557     }
558
559     # amount should always be a positive value
560     my $amount = $params->{amount};
561     unless ( $amount > 0 ) {
562         Koha::Exceptions::Account::AmountNotPositive->throw(
563             error => 'Debit amount passed is not positive' );
564     }
565
566     my $description = $params->{description} // q{};
567     my $note        = $params->{note} // q{};
568     my $user_id     = $params->{user_id};
569     my $interface   = $params->{interface};
570     my $library_id  = $params->{library_id};
571     my $debit_type  = $params->{type};
572     my $item_id     = $params->{item_id};
573     my $issue_id    = $params->{issue_id};
574     my $offset_type = $Koha::Account::offset_type->{$debit_type} // 'Manual Debit';
575
576     my $line;
577     my $schema = Koha::Database->new->schema;
578     try {
579         $schema->txn_do(
580             sub {
581
582                 # Insert the account line
583                 $line = Koha::Account::Line->new(
584                     {
585                         borrowernumber    => $self->{patron_id},
586                         date              => \'NOW()',
587                         amount            => $amount,
588                         description       => $description,
589                         debit_type_code   => $debit_type,
590                         amountoutstanding => $amount,
591                         payment_type      => undef,
592                         note              => $note,
593                         manager_id        => $user_id,
594                         interface         => $interface,
595                         itemnumber        => $item_id,
596                         issue_id          => $issue_id,
597                         branchcode        => $library_id,
598                         (
599                             $debit_type eq 'OVERDUE'
600                             ? ( status => 'UNRETURNED' )
601                             : ()
602                         ),
603                     }
604                 )->store();
605
606                 # Record the account offset
607                 my $account_offset = Koha::Account::Offset->new(
608                     {
609                         debit_id => $line->id,
610                         type     => $offset_type,
611                         amount   => $amount
612                     }
613                 )->store();
614
615                 if ( C4::Context->preference("FinesLog") ) {
616                     logaction(
617                         "FINES", 'CREATE',
618                         $self->{patron_id},
619                         Dumper(
620                             {
621                                 action            => "create_$debit_type",
622                                 borrowernumber    => $self->{patron_id},
623                                 amount            => $amount,
624                                 description       => $description,
625                                 amountoutstanding => $amount,
626                                 debit_type_code   => $debit_type,
627                                 note              => $note,
628                                 itemnumber        => $item_id,
629                                 manager_id        => $user_id,
630                             }
631                         ),
632                         $interface
633                     );
634                 }
635             }
636         );
637     }
638     catch {
639         if ( ref($_) eq 'Koha::Exceptions::Object::FKConstraint' ) {
640             if ( $_->broken_fk eq 'debit_type_code' ) {
641                 Koha::Exceptions::Account::UnrecognisedType->throw(
642                     error => 'Type of debit not recognised' );
643             }
644             else {
645                 $_->rethrow;
646             }
647         }
648     };
649
650     return $line;
651 }
652
653 =head3 balance
654
655 my $balance = $self->balance
656
657 Return the balance (sum of amountoutstanding columns)
658
659 =cut
660
661 sub balance {
662     my ($self) = @_;
663     return $self->lines->total_outstanding;
664 }
665
666 =head3 outstanding_debits
667
668 my $lines = Koha::Account->new({ patron_id => $patron_id })->outstanding_debits;
669
670 It returns the debit lines with outstanding amounts for the patron.
671
672 In scalar context, it returns a Koha::Account::Lines iterator. In list context, it will
673 return a list of Koha::Account::Line objects.
674
675 =cut
676
677 sub outstanding_debits {
678     my ($self) = @_;
679
680     return $self->lines->search(
681         {
682             amount            => { '>' => 0 },
683             amountoutstanding => { '>' => 0 }
684         }
685     );
686 }
687
688 =head3 outstanding_credits
689
690 my $lines = Koha::Account->new({ patron_id => $patron_id })->outstanding_credits;
691
692 It returns the credit lines with outstanding amounts for the patron.
693
694 In scalar context, it returns a Koha::Account::Lines iterator. In list context, it will
695 return a list of Koha::Account::Line objects.
696
697 =cut
698
699 sub outstanding_credits {
700     my ($self) = @_;
701
702     return $self->lines->search(
703         {
704             amount            => { '<' => 0 },
705             amountoutstanding => { '<' => 0 }
706         }
707     );
708 }
709
710 =head3 non_issues_charges
711
712 my $non_issues_charges = $self->non_issues_charges
713
714 Calculates amount immediately owing by the patron - non-issue charges.
715
716 Charges exempt from non-issue are:
717 * Res (holds) if HoldsInNoissuesCharge syspref is set to false
718 * Rent (rental) if RentalsInNoissuesCharge syspref is set to false
719 * Manual invoices if ManInvInNoissuesCharge syspref is set to false
720
721 =cut
722
723 sub non_issues_charges {
724     my ($self) = @_;
725
726     #NOTE: With bug 23049 these preferences could be moved to being attached
727     #to individual debit types to give more flexability and specificity.
728     my @not_fines;
729     push @not_fines, 'RESERVE'
730       unless C4::Context->preference('HoldsInNoissuesCharge');
731     push @not_fines, ( 'RENT', 'RENT_DAILY', 'RENT_RENEW', 'RENT_DAILY_RENEW' )
732       unless C4::Context->preference('RentalsInNoissuesCharge');
733     unless ( C4::Context->preference('ManInvInNoissuesCharge') ) {
734         my @man_inv = Koha::Account::DebitTypes->search({ is_system => 0 })->get_column('code');
735         push @not_fines, @man_inv;
736     }
737
738     return $self->lines->search(
739         {
740             debit_type_code => { -not_in => \@not_fines }
741         },
742     )->total_outstanding;
743 }
744
745 =head3 lines
746
747 my $lines = $self->lines;
748
749 Return all credits and debits for the user, outstanding or otherwise
750
751 =cut
752
753 sub lines {
754     my ($self) = @_;
755
756     return Koha::Account::Lines->search(
757         {
758             borrowernumber => $self->{patron_id},
759         }
760     );
761 }
762
763 =head3 reconcile_balance
764
765 $account->reconcile_balance();
766
767 Find outstanding credits and use them to pay outstanding debits.
768 Currently, this implicitly uses the 'First In First Out' rule for
769 applying credits against debits.
770
771 =cut
772
773 sub reconcile_balance {
774     my ($self) = @_;
775
776     my $outstanding_debits  = $self->outstanding_debits;
777     my $outstanding_credits = $self->outstanding_credits;
778
779     while (     $outstanding_debits->total_outstanding > 0
780             and my $credit = $outstanding_credits->next )
781     {
782         # there's both outstanding debits and credits
783         $credit->apply( { debits => [ $outstanding_debits->as_list ] } );    # applying credit, no special offset
784
785         $outstanding_debits = $self->outstanding_debits;
786
787     }
788
789     return $self;
790 }
791
792 1;
793
794 =head2 Name mappings
795
796 =head3 $offset_type
797
798 =cut
799
800 our $offset_type = {
801     'CREDIT'           => 'Manual Credit',
802     'FORGIVEN'         => 'Writeoff',
803     'LOST_FOUND'       => 'Lost Item Found',
804     'PAYMENT'          => 'Payment',
805     'WRITEOFF'         => 'Writeoff',
806     'ACCOUNT'          => 'Account Fee',
807     'ACCOUNT_RENEW'    => 'Account Fee',
808     'RESERVE'          => 'Reserve Fee',
809     'PROCESSING'       => 'Processing Fee',
810     'LOST'             => 'Lost Item',
811     'RENT'             => 'Rental Fee',
812     'RENT_DAILY'       => 'Rental Fee',
813     'RENT_RENEW'       => 'Rental Fee',
814     'RENT_DAILY_RENEW' => 'Rental Fee',
815     'OVERDUE'          => 'OVERDUE',
816     'RESERVE_EXPIRED'  => 'Hold Expired'
817 };
818
819 =head1 AUTHORS
820
821 =encoding utf8
822
823 Kyle M Hall <kyle.m.hall@gmail.com>
824 Tomás Cohen Arazi <tomascohen@gmail.com>
825 Martin Renvoize <martin.renvoize@ptfs-europe.com>
826
827 =cut