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
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Data::Dumper qw( Dumper );
22 use C4::Log qw( logaction );
24 use Koha::Account::CreditType;
25 use Koha::Account::DebitType;
26 use Koha::Account::Offsets;
28 use Koha::DateUtils qw( dt_from_string );
29 use Koha::Exceptions::Account;
32 use base qw(Koha::Object Koha::Object::Mixin::AdditionalFields);
38 Koha::Account::Line - Koha accountline Object class
48 Return the patron linked to this account line
54 my $rs = $self->_result->borrowernumber;
56 return Koha::Patron->_new_from_dbic( $rs );
61 Return the manager linked to this account line
67 my $rs = $self->_result->manager;
69 return Koha::Patron->_new_from_dbic( $rs );
74 Return the item linked to this account line if exists
80 my $rs = $self->_result->itemnumber;
82 return Koha::Item->_new_from_dbic( $rs );
87 Return the checkout linked to this account line if exists
93 return unless $self->issue_id;
95 return Koha::Checkouts->find( $self->issue_id )
96 || Koha::Old::Checkouts->find( $self->issue_id );
101 Returns a Koha::Library object representing where the accountline was recorded
107 my $rs = $self->_result->library;
109 return Koha::Library->_new_from_dbic($rs);
114 Return the credit_type linked to this account line
120 my $rs = $self->_result->credit_type_code;
122 return Koha::Account::CreditType->_new_from_dbic( $rs );
127 Return the debit_type linked to this account line
133 my $rs = $self->_result->debit_type_code;
135 return Koha::Account::DebitType->_new_from_dbic( $rs );
138 =head3 credit_offsets
140 Return the credit_offsets linked to this account line if some exist
145 my ( $self, $cond, $attr ) = @_;
147 unless ( $self->is_credit ) {
148 Koha::Exceptions::Account::IsNotCredit->throw(
149 error => 'Account line ' . $self->id . ' is not a credit'
153 my $rs = $self->_result->search_related( 'account_offsets_credits', $cond, $attr);
155 return Koha::Account::Offsets->_new_from_dbic($rs);
160 Return the debit_offsets linked to this account line if some exist
165 my ( $self, $cond, $attr ) = @_;
167 unless ( $self->is_debit ) {
168 Koha::Exceptions::Account::IsNotDebit->throw(
169 error => 'Account line ' . $self->id . ' is not a debit'
173 my $rs = $self->_result->search_related( 'account_offsets_debits', $cond, $attr);
175 return Koha::Account::Offsets->_new_from_dbic($rs);
180 my $credits = $accountline->credits;
181 my $credits = $accountline->credits( $cond, $attr );
183 Return the credits linked to this account line if some exist.
184 Search conditions and attributes may be passed if you wish to filter
185 the resultant resultant resultset.
190 my ( $self, $cond, $attr ) = @_;
192 unless ( $self->is_debit ) {
193 Koha::Exceptions::Account::IsNotDebit->throw(
194 error => 'Account line ' . $self->id . ' is not a debit'
198 my $cond_m = { map { "credit.".$_ => $cond->{$_} } keys %{$cond}};
200 $self->_result->search_related('account_offsets_debits')
201 ->search_related( 'credit', $cond_m, $attr );
203 return Koha::Account::Lines->_new_from_dbic($rs);
208 my $debits = $accountline->debits;
209 my $debits = $accountline->debits( $cond, $attr );
211 Return the debits linked to this account line if some exist.
212 Search conditions and attributes may be passed if you wish to filter
213 the resultant resultant resultset.
218 my ( $self, $cond, $attr ) = @_;
220 unless ( $self->is_credit ) {
221 Koha::Exceptions::Account::IsNotCredit->throw(
222 error => 'Account line ' . $self->id . ' is not a credit'
226 my $cond_m = { map { "debit.".$_ => $cond->{$_} } keys %{$cond}};
228 $self->_result->search_related('account_offsets_credits')
229 ->search_related( 'debit', $cond_m, $attr );
231 return Koha::Account::Lines->_new_from_dbic($rs);
236 $payment_accountline->void({
237 interface => $interface,
238 [ staff_id => $staff_id, branch => $branchcode ]
241 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
242 created by the application of this credit upon any debits and mark the credit
243 as 'void' by updating it's status to "VOID".
248 my ($self, $params) = @_;
250 # Make sure it is a credit we are voiding
251 unless ( $self->is_credit ) {
252 Koha::Exceptions::Account::IsNotCredit->throw(
253 error => 'Account line ' . $self->id . 'is not a credit' );
256 # Make sure it is not already voided
257 if ( $self->status && $self->status eq 'VOID' ) {
258 Koha::Exceptions::Account->throw(
259 error => 'Account line ' . $self->id . 'is already void' );
262 # Check for mandatory parameters
263 my @mandatory = ( 'interface' );
264 for my $param (@mandatory) {
265 unless ( defined( $params->{$param} ) ) {
266 Koha::Exceptions::MissingParameter->throw(
267 error => "The $param parameter is mandatory" );
271 # More mandatory parameters
272 if ( $params->{interface} eq 'intranet' ) {
273 my @optional = ( 'staff_id', 'branch' );
274 for my $param (@optional) {
275 unless ( defined( $params->{$param} ) ) {
276 Koha::Exceptions::MissingParameter->throw( error =>
277 "The $param parameter is mandatory when interface is set to 'intranet'"
283 # Find any applied offsets for the credit so we may reverse them
284 my @account_offsets =
285 Koha::Account::Offsets->search(
286 { credit_id => $self->id, amount => { '<' => 0 } } )->as_list;
289 $self->_result->result_source->schema->txn_do(
292 # A 'void' is a 'debit'
293 $void = Koha::Account::Line->new(
295 borrowernumber => $self->borrowernumber,
297 debit_type_code => 'VOID',
298 amount => $self->amount * -1,
299 amountoutstanding => $self->amount * -1,
300 manager_id => $params->{staff_id},
301 interface => $params->{interface},
302 branchcode => $params->{branch},
306 # Record the creation offset
307 Koha::Account::Offset->new(
309 debit_id => $void->id,
311 amount => $self->amount * -1
315 # Link void to payment
317 amountoutstanding => $self->amount,
320 $self->apply( { debits => [$void] } );
322 # Reverse any applied payments
323 foreach my $account_offset (@account_offsets) {
325 Koha::Account::Lines->find( $account_offset->debit_id );
327 next unless $fee_paid;
329 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
330 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
331 $fee_paid->amountoutstanding($new_amount);
334 Koha::Account::Offset->new(
336 credit_id => $self->id,
337 debit_id => $fee_paid->id,
338 amount => $amount_paid,
344 if ( C4::Context->preference("FinesLog") ) {
347 $self->borrowernumber,
350 action => 'void_payment',
351 borrowernumber => $self->borrowernumber,
352 amount => $self->amount,
353 amountoutstanding => $self->amountoutstanding,
354 description => $self->description,
355 credit_type_code => $self->credit_type_code,
356 payment_type => $self->payment_type,
358 itemnumber => $self->itemnumber,
359 manager_id => $self->manager_id,
361 [ map { $_->unblessed } @account_offsets ],
369 $void->discard_changes;
375 $debit_accountline->cancel();
377 Cancel a charge. It will mark the debit as 'cancelled' by updating its
378 status to 'CANCELLED'.
380 Charges that have been fully or partially paid cannot be cancelled.
382 Returns the cancellation accountline.
387 my ( $self, $params ) = @_;
389 # Make sure it is a charge we are reducing
390 unless ( $self->is_debit ) {
391 Koha::Exceptions::Account::IsNotDebit->throw(
392 error => 'Account line ' . $self->id . 'is not a debit' );
394 if ( $self->debit_type_code eq 'PAYOUT' ) {
395 Koha::Exceptions::Account::IsNotDebit->throw(
396 error => 'Account line ' . $self->id . 'is a payout' );
399 # Make sure it is not already cancelled
400 if ( $self->status && $self->status eq 'CANCELLED' ) {
401 Koha::Exceptions::Account->throw(
402 error => 'Account line ' . $self->id . 'is already cancelled' );
405 # Make sure it has not be paid yet
406 if ( $self->amount != $self->amountoutstanding ) {
407 Koha::Exceptions::Account->throw(
408 error => 'Account line ' . $self->id . 'is already offset' );
411 # Check for mandatory parameters
412 my @mandatory = ( 'staff_id', 'branch' );
413 for my $param (@mandatory) {
414 unless ( defined( $params->{$param} ) ) {
415 Koha::Exceptions::MissingParameter->throw(
416 error => "The $param parameter is mandatory" );
421 $self->_result->result_source->schema->txn_do(
424 # A 'cancellation' is a 'credit'
425 $cancellation = Koha::Account::Line->new(
428 amount => 0 - $self->amount,
429 credit_type_code => 'CANCELLATION',
431 amountoutstanding => 0 - $self->amount,
432 manager_id => $params->{staff_id},
433 borrowernumber => $self->borrowernumber,
434 interface => 'intranet',
435 branchcode => $params->{branch},
439 my $cancellation_offset = Koha::Account::Offset->new(
441 credit_id => $cancellation->accountlines_id,
443 amount => 0 - $self->amount
447 # Link cancellation to charge
448 $cancellation->apply( { debits => [$self] } );
449 $cancellation->status('APPLIED')->store();
451 # Update status of original debit
452 $self->status('CANCELLED')->store;
456 $cancellation->discard_changes;
457 return $cancellation;
462 $charge_accountline->reduce({
463 reduction_type => $reduction_type
466 Used to 'reduce' a charge/debit by adding a credit to offset against the amount
469 May be used to apply a discount whilst retaining the original debit amounts or
470 to apply a full or partial refund for example when a lost item is found and
473 It will immediately be applied to the given debit unless the debit has already
474 been paid, in which case a 'zero' offset will be added to maintain a link to
475 the debit but the outstanding credit will be left so it may be applied to other
478 Reduction type may be one of:
483 Returns the reduction accountline (which will be a credit)
488 my ( $self, $params ) = @_;
490 # Make sure it is a charge we are reducing
491 unless ( $self->is_debit ) {
492 Koha::Exceptions::Account::IsNotDebit->throw(
493 error => 'Account line ' . $self->id . 'is not a debit' );
495 if ( $self->debit_type_code eq 'PAYOUT' ) {
496 Koha::Exceptions::Account::IsNotDebit->throw(
497 error => 'Account line ' . $self->id . 'is a payout' );
500 # Check for mandatory parameters
501 my @mandatory = ( 'interface', 'reduction_type', 'amount' );
502 for my $param (@mandatory) {
503 unless ( defined( $params->{$param} ) ) {
504 Koha::Exceptions::MissingParameter->throw(
505 error => "The $param parameter is mandatory" );
509 # More mandatory parameters
510 if ( $params->{interface} eq 'intranet' ) {
511 my @optional = ( 'staff_id', 'branch' );
512 for my $param (@optional) {
513 unless ( defined( $params->{$param} ) ) {
514 Koha::Exceptions::MissingParameter->throw( error =>
515 "The $param parameter is mandatory when interface is set to 'intranet'"
521 # Make sure the reduction isn't more than the original
522 my $original = $self->amount;
523 Koha::Exceptions::Account::AmountNotPositive->throw(
524 error => 'Reduce amount passed is not positive' )
525 unless ( $params->{amount} > 0 );
526 Koha::Exceptions::ParameterTooHigh->throw( error =>
527 "Amount to reduce ($params->{amount}) is higher than original amount ($original)"
528 ) unless ( $original >= $params->{amount} );
530 $self->credits( { credit_type_code => [ 'DISCOUNT', 'REFUND' ] } )->total;
531 Koha::Exceptions::ParameterTooHigh->throw( error =>
532 "Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
535 unless ( $original >= ( $params->{amount} + abs($reduced) ) );
537 my $status = { 'REFUND' => 'REFUNDED', 'DISCOUNT' => 'DISCOUNTED' };
540 $self->_result->result_source->schema->txn_do(
543 # A 'reduction' is a 'credit'
544 $reduction = Koha::Account::Line->new(
547 amount => 0 - $params->{amount},
548 credit_type_code => $params->{reduction_type},
550 amountoutstanding => 0 - $params->{amount},
551 manager_id => $params->{staff_id},
552 borrowernumber => $self->borrowernumber,
553 interface => $params->{interface},
554 branchcode => $params->{branch},
558 my $reduction_offset = Koha::Account::Offset->new(
560 credit_id => $reduction->accountlines_id,
562 amount => 0 - $params->{amount}
566 # Link reduction to charge (and apply as required)
567 my $debit_outstanding = $self->amountoutstanding;
568 if ( $debit_outstanding >= $params->{amount} ) {
570 $reduction->apply( { debits => [$self] } );
571 $reduction->status('APPLIED')->store();
575 # Zero amount offset used to link original 'debit' to
577 my $link_reduction_offset = Koha::Account::Offset->new(
579 credit_id => $reduction->accountlines_id,
580 debit_id => $self->accountlines_id,
587 # Update status of original debit
588 $self->status( $status->{ $params->{reduction_type} } )->store;
592 $reduction->discard_changes;
598 my $debits = $account->outstanding_debits;
599 my $credit = $credit->apply( { debits => $debits } );
601 Applies the credit to a given debits array reference.
603 =head4 arguments hashref
607 =item debits - Koha::Account::Lines object set of debits
614 my ( $self, $params ) = @_;
616 my $debits = $params->{debits};
618 unless ( $self->is_credit ) {
619 Koha::Exceptions::Account::IsNotCredit->throw(
620 error => 'Account line ' . $self->id . ' is not a credit'
624 my $available_credit = $self->amountoutstanding * -1;
626 unless ( $available_credit > 0 ) {
627 Koha::Exceptions::Account::NoAvailableCredit->throw(
628 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
632 my $schema = Koha::Database->new->schema;
634 $schema->txn_do( sub {
635 for my $debit ( @{$debits} ) {
637 unless ( $debit->is_debit ) {
638 Koha::Exceptions::Account::IsNotDebit->throw(
639 error => 'Account line ' . $debit->id . 'is not a debit'
642 my $amount_to_cancel;
643 my $owed = $debit->amountoutstanding;
645 if ( $available_credit >= $owed ) {
646 $amount_to_cancel = $owed;
648 else { # $available_credit < $debit->amountoutstanding
649 $amount_to_cancel = $available_credit;
652 # record the account offset
653 Koha::Account::Offset->new(
654 { credit_id => $self->id,
655 debit_id => $debit->id,
656 amount => $amount_to_cancel * -1,
661 $available_credit -= $amount_to_cancel;
663 $self->amountoutstanding( $available_credit * -1 )->store;
664 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
666 # Attempt to renew the item associated with this debit if
668 if ( $self->credit_type_code ne 'FORGIVEN' && $debit->is_renewable ) {
669 my $outcome = $debit->renew_item( { interface => $params->{interface} } );
673 message => 'renewal',
678 $debit->discard_changes; # Refresh values from DB to clear floating point remainders
680 # Same logic exists in Koha::Account::pay
682 C4::Context->preference('MarkLostItemsAsReturned') =~
684 && $debit->debit_type_code
685 && $debit->debit_type_code eq 'LOST'
686 && $debit->amountoutstanding == 0
687 && $debit->itemnumber
689 $self->credit_type_code eq 'LOST_FOUND'
690 && $self->itemnumber == $debit->itemnumber
694 C4::Circulation::ReturnLostItem( $self->borrowernumber,
695 $debit->itemnumber );
698 last if $available_credit == 0;
707 $credit_accountline->payout(
709 payout_type => $payout_type,
710 register_id => $register_id,
711 staff_id => $staff_id,
712 interface => 'intranet',
717 Used to 'pay out' a credit to a user.
719 Payout type may be one of any existing payment types
721 Returns the payout debit line that is created via this transaction.
726 my ( $self, $params ) = @_;
728 # Make sure it is a credit we are paying out
729 unless ( $self->is_credit ) {
730 Koha::Exceptions::Account::IsNotCredit->throw(
731 error => 'Account line ' . $self->id . ' is not a credit' );
734 # Check for mandatory parameters
736 ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
737 for my $param (@mandatory) {
738 unless ( defined( $params->{$param} ) ) {
739 Koha::Exceptions::MissingParameter->throw(
740 error => "The $param parameter is mandatory" );
744 # Make sure there is outstanding credit to pay out
745 my $outstanding = -1 * $self->amountoutstanding;
747 $params->{amount} ? $params->{amount} : $outstanding;
748 Koha::Exceptions::Account::AmountNotPositive->throw(
749 error => 'Payout amount passed is not positive' )
750 unless ( $amount > 0 );
751 Koha::Exceptions::ParameterTooHigh->throw(
752 error => "Amount to payout ($amount) is higher than amountoutstanding ($outstanding)" )
753 unless ($outstanding >= $amount );
755 # Make sure we record the cash register for cash transactions
756 Koha::Exceptions::Account::RegisterRequired->throw()
757 if ( C4::Context->preference("UseCashRegisters")
758 && defined( $params->{payout_type} )
759 && ( $params->{payout_type} eq 'CASH' || $params->{payout_type} eq 'SIP00' )
760 && !defined( $params->{cash_register} ) );
763 $self->_result->result_source->schema->txn_do(
766 # A 'payout' is a 'debit'
767 $payout = Koha::Account::Line->new(
771 debit_type_code => 'PAYOUT',
772 payment_type => $params->{payout_type},
773 amountoutstanding => $amount,
774 manager_id => $params->{staff_id},
775 borrowernumber => $self->borrowernumber,
776 interface => $params->{interface},
777 branchcode => $params->{branch},
778 register_id => $params->{cash_register}
782 my $payout_offset = Koha::Account::Offset->new(
784 debit_id => $payout->accountlines_id,
790 $self->apply( { debits => [$payout] } );
791 $self->status('PAID')->store;
795 $payout->discard_changes;
801 This method allows updating a debit or credit on a patron's account
803 $account_line->adjust(
806 type => $update_type,
807 interface => $interface
811 $update_type can be any of:
814 Authors Note: The intention here is that this method is only used
815 to adjust accountlines where the final amount is not yet known/fixed.
816 Incrementing fines are the only existing case at the time of writing,
817 all other forms of 'adjustment' should be recorded as distinct credits
818 or debits and applied, via an offset, to the corresponding debit or credit.
823 my ( $self, $params ) = @_;
825 my $amount = $params->{amount};
826 my $update_type = $params->{type};
827 my $interface = $params->{interface};
829 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
830 Koha::Exceptions::Account::UnrecognisedType->throw(
831 error => 'Update type not recognised'
835 my $debit_type_code = $self->debit_type_code;
836 my $account_status = $self->status;
840 $Koha::Account::Line::allowed_update->{$update_type}
843 && ( $Koha::Account::Line::allowed_update->{$update_type}
844 ->{$debit_type_code} eq $account_status )
848 Koha::Exceptions::Account::UnrecognisedType->throw(
849 error => 'Update type not allowed on this debit_type' );
852 my $schema = Koha::Database->new->schema;
857 my $amount_before = $self->amount;
858 my $amount_outstanding_before = $self->amountoutstanding;
859 my $difference = $amount - $amount_before;
860 my $new_outstanding = $amount_outstanding_before + $difference;
862 my $offset_type = $debit_type_code;
863 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
865 # Catch cases that require patron refunds
866 if ( $new_outstanding < 0 ) {
868 Koha::Patrons->find( $self->borrowernumber )->account;
869 my $credit = $account->add_credit(
871 amount => $new_outstanding * -1,
872 type => 'OVERPAYMENT',
873 interface => $interface,
874 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
877 $new_outstanding = 0;
880 # Update the account line
885 amountoutstanding => $new_outstanding,
889 # Record the account offset
890 my $account_offset = Koha::Account::Offset->new(
892 debit_id => $self->id,
893 type => $offset_type,
894 amount => $difference
898 if ( C4::Context->preference("FinesLog") ) {
900 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
901 $self->borrowernumber,
903 { action => $update_type,
904 borrowernumber => $self->borrowernumber,
906 description => undef,
907 amountoutstanding => $new_outstanding,
908 debit_type_code => $self->debit_type_code,
910 itemnumber => $self->itemnumber,
914 ) if ( $update_type eq 'overdue_update' );
924 my $bool = $line->is_credit;
931 return defined $self->credit_type_code;
936 my $bool = $line->is_debit;
943 return !$self->is_credit;
946 =head3 to_api_mapping
948 This method returns the mapping for representing a Koha::Account::Line object
955 accountlines_id => 'account_line_id',
956 credit_type_code => 'credit_type',
957 debit_type_code => 'debit_type',
958 amountoutstanding => 'amount_outstanding',
959 borrowernumber => 'patron_id',
960 branchcode => 'library_id',
961 issue_id => 'checkout_id',
962 itemnumber => 'item_id',
963 manager_id => 'user_id',
964 note => 'internal_note',
965 register_id => 'cash_register_id',
972 my $bool = $line->is_renewable;
980 $self->amountoutstanding == 0 &&
981 $self->debit_type_code &&
982 $self->debit_type_code eq 'OVERDUE' &&
984 $self->status eq 'UNRETURNED' &&
992 my $renew_result = $line->renew_item;
994 Conditionally attempt to renew an item and return the outcome. This is
995 as a consequence of the fine on an item being fully paid off.
996 Caller must call is_renewable before.
1001 my ($self, $params) = @_;
1005 # We want to reject the call to renew if:
1006 # - The RenewAccruingItemWhenPaid syspref is off
1008 # - The RenewAccruingItemInOpac syspref is off
1009 # - There is an interface param passed and it's value is 'opac'
1012 !C4::Context->preference('RenewAccruingItemWhenPaid') ||
1014 !C4::Context->preference('RenewAccruingItemInOpac') &&
1015 $params->{interface} &&
1016 $params->{interface} eq 'opac'
1022 my $itemnumber = $self->item->itemnumber;
1023 my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1025 $self->item->checkout
1028 my $borrowernumber = $self->patron->borrowernumber;
1029 my $due_date = C4::Circulation::AddRenewal(
1031 borrowernumber => $borrowernumber,
1032 itemnumber => $itemnumber,
1033 branch => $self->{branchcode},
1038 itemnumber => $itemnumber,
1039 due_date => $due_date,
1044 itemnumber => $itemnumber,
1054 Specific store method to generate credit number before saving
1061 my $AutoCreditNumber = C4::Context->preference('AutoCreditNumber');
1062 my $credit_number_enabled = $self->is_credit && $self->credit_type->credit_number_enabled;
1064 if ($AutoCreditNumber && $credit_number_enabled && !$self->in_storage) {
1065 if (defined $self->credit_number) {
1066 Koha::Exceptions::Account->throw('AutoCreditNumber is enabled but credit_number is already defined');
1069 my $rs = Koha::Database->new->schema->resultset($self->_type);
1071 if ($AutoCreditNumber eq 'incremental') {
1072 my $max = $rs->search({
1073 credit_number => { -regexp => '^[0-9]+$' }
1075 select => \'CAST(credit_number AS UNSIGNED)',
1076 as => ['credit_number'],
1077 })->get_column('credit_number')->max;
1079 $self->credit_number($max + 1);
1080 } elsif ($AutoCreditNumber eq 'annual') {
1081 my $now = dt_from_string;
1082 my $prefix = sprintf('%d-', $now->year);
1083 my $max = $rs->search({
1085 credit_number => { -regexp => '[0-9]{4}$' },
1086 credit_number => { -like => "$prefix%" },
1088 })->get_column('credit_number')->max;
1089 $max //= $prefix . '0000';
1090 my $incr = substr($max, length $prefix);
1091 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1092 } elsif ($AutoCreditNumber eq 'branchyyyymmincr') {
1093 my $userenv = C4::Context->userenv;
1095 my $branch = $userenv->{branch};
1096 my $now = dt_from_string;
1097 my $prefix = sprintf('%s%d%02d', $branch, $now->year, $now->month);
1098 my $pattern = $prefix;
1099 $pattern =~ s/([\?%_])/\\$1/g;
1100 my $max = $rs->search({
1102 credit_number => { -regexp => '[0-9]{4}$' },
1103 credit_number => { -like => "$pattern%" },
1105 })->get_column('credit_number')->max;
1106 $max //= $prefix . '0000';
1107 my $incr = substr($max, length $prefix);
1108 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1113 return $self->SUPER::store();
1116 =head2 Internal methods
1125 return 'Accountline';
1130 =head2 Name mappings
1132 =head3 $allowed_update
1136 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
1140 Kyle M Hall <kyle@bywatersolutions.com >
1141 Tomás Cohen Arazi <tomascohen@theke.io>
1142 Martin Renvoize <martin.renvoize@ptfs-europe.com>