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 );
23 use C4::Overdues qw( UpdateFine );
25 use Koha::Account::CreditType;
26 use Koha::Account::DebitType;
27 use Koha::Account::Offsets;
29 use Koha::DateUtils qw( dt_from_string );
30 use Koha::Exceptions::Account;
33 use base qw(Koha::Object Koha::Object::Mixin::AdditionalFields);
39 Koha::Account::Line - Koha accountline Object class
49 Return the patron linked to this account line
55 my $rs = $self->_result->borrowernumber;
57 return Koha::Patron->_new_from_dbic( $rs );
62 Return the manager linked to this account line
68 my $rs = $self->_result->manager;
70 return Koha::Patron->_new_from_dbic( $rs );
75 Return the item linked to this account line if exists
81 my $rs = $self->_result->itemnumber;
83 return Koha::Item->_new_from_dbic( $rs );
88 Return the checkout linked to this account line if exists
94 return unless $self->issue_id ;
96 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
97 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
98 return $self->{_checkout};
103 Returns a Koha::Library object representing where the accountline was recorded
109 my $rs = $self->_result->library;
111 return Koha::Library->_new_from_dbic($rs);
116 Return the credit_type linked to this account line
122 my $rs = $self->_result->credit_type_code;
124 return Koha::Account::CreditType->_new_from_dbic( $rs );
129 Return the debit_type linked to this account line
135 my $rs = $self->_result->debit_type_code;
137 return Koha::Account::DebitType->_new_from_dbic( $rs );
140 =head3 credit_offsets
142 Return the credit_offsets linked to this account line if some exist
147 my ( $self, $cond, $attr ) = @_;
149 unless ( $self->is_credit ) {
150 Koha::Exceptions::Account::IsNotCredit->throw(
151 error => 'Account line ' . $self->id . ' is not a credit'
155 my $rs = $self->_result->search_related( 'account_offsets_credits', $cond, $attr);
157 return Koha::Account::Offsets->_new_from_dbic($rs);
162 Return the debit_offsets linked to this account line if some exist
167 my ( $self, $cond, $attr ) = @_;
169 unless ( $self->is_debit ) {
170 Koha::Exceptions::Account::IsNotDebit->throw(
171 error => 'Account line ' . $self->id . ' is not a debit'
175 my $rs = $self->_result->search_related( 'account_offsets_debits', $cond, $attr);
177 return Koha::Account::Offsets->_new_from_dbic($rs);
182 my $credits = $accountline->credits;
183 my $credits = $accountline->credits( $cond, $attr );
185 Return the credits linked to this account line if some exist.
186 Search conditions and attributes may be passed if you wish to filter
187 the resultant resultant resultset.
192 my ( $self, $cond, $attr ) = @_;
194 unless ( $self->is_debit ) {
195 Koha::Exceptions::Account::IsNotDebit->throw(
196 error => 'Account line ' . $self->id . ' is not a debit'
200 my $cond_m = { map { "credit.".$_ => $cond->{$_} } keys %{$cond}};
202 $self->_result->search_related('account_offsets_debits')
203 ->search_related( 'credit', $cond_m, $attr );
205 return Koha::Account::Lines->_new_from_dbic($rs);
210 my $debits = $accountline->debits;
211 my $debits = $accountline->debits( $cond, $attr );
213 Return the debits linked to this account line if some exist.
214 Search conditions and attributes may be passed if you wish to filter
215 the resultant resultant resultset.
220 my ( $self, $cond, $attr ) = @_;
222 unless ( $self->is_credit ) {
223 Koha::Exceptions::Account::IsNotCredit->throw(
224 error => 'Account line ' . $self->id . ' is not a credit'
228 my $cond_m = { map { "debit.".$_ => $cond->{$_} } keys %{$cond}};
230 $self->_result->search_related('account_offsets_credits')
231 ->search_related( 'debit', $cond_m, $attr );
233 return Koha::Account::Lines->_new_from_dbic($rs);
238 $payment_accountline->void({
239 interface => $interface,
240 [ staff_id => $staff_id, branch => $branchcode ]
243 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
244 created by the application of this credit upon any debits and mark the credit
245 as 'void' by updating it's status to "VOID".
250 my ($self, $params) = @_;
252 # Make sure it is a credit we are voiding
253 unless ( $self->is_credit ) {
254 Koha::Exceptions::Account::IsNotCredit->throw(
255 error => 'Account line ' . $self->id . 'is not a credit' );
258 # Make sure it is not already voided
259 if ( $self->status && $self->status eq 'VOID' ) {
260 Koha::Exceptions::Account->throw(
261 error => 'Account line ' . $self->id . 'is already void' );
264 # Check for mandatory parameters
265 my @mandatory = ( 'interface' );
266 for my $param (@mandatory) {
267 unless ( defined( $params->{$param} ) ) {
268 Koha::Exceptions::MissingParameter->throw(
269 error => "The $param parameter is mandatory" );
273 # More mandatory parameters
274 if ( $params->{interface} eq 'intranet' ) {
275 my @optional = ( 'staff_id', 'branch' );
276 for my $param (@optional) {
277 unless ( defined( $params->{$param} ) ) {
278 Koha::Exceptions::MissingParameter->throw( error =>
279 "The $param parameter is mandatory when interface is set to 'intranet'"
285 # Find any applied offsets for the credit so we may reverse them
286 my @account_offsets =
287 Koha::Account::Offsets->search(
288 { credit_id => $self->id, amount => { '<' => 0 } } )->as_list;
291 $self->_result->result_source->schema->txn_do(
294 # A 'void' is a 'debit'
295 $void = Koha::Account::Line->new(
297 borrowernumber => $self->borrowernumber,
299 debit_type_code => 'VOID',
300 amount => $self->amount * -1,
301 amountoutstanding => $self->amount * -1,
302 manager_id => $params->{staff_id},
303 interface => $params->{interface},
304 branchcode => $params->{branch},
308 # Record the creation offset
309 Koha::Account::Offset->new(
311 debit_id => $void->id,
313 amount => $self->amount * -1
317 # Link void to payment
319 amountoutstanding => $self->amount,
322 $self->apply( { debits => [$void] } );
324 # Reverse any applied payments
325 foreach my $account_offset (@account_offsets) {
327 Koha::Account::Lines->find( $account_offset->debit_id );
329 next unless $fee_paid;
331 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
332 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
333 $fee_paid->amountoutstanding($new_amount);
336 Koha::Account::Offset->new(
338 credit_id => $self->id,
339 debit_id => $fee_paid->id,
340 amount => $amount_paid,
346 if ( C4::Context->preference("FinesLog") ) {
349 $self->borrowernumber,
352 action => 'void_payment',
353 borrowernumber => $self->borrowernumber,
354 amount => $self->amount,
355 amountoutstanding => $self->amountoutstanding,
356 description => $self->description,
357 credit_type_code => $self->credit_type_code,
358 payment_type => $self->payment_type,
360 itemnumber => $self->itemnumber,
361 manager_id => $self->manager_id,
363 [ map { $_->unblessed } @account_offsets ],
371 $void->discard_changes;
377 $debit_accountline->cancel();
379 Cancel a charge. It will mark the debit as 'cancelled' by updating its
380 status to 'CANCELLED'.
382 Charges that have been fully or partially paid cannot be cancelled.
384 Returns the cancellation accountline.
389 my ( $self, $params ) = @_;
391 # Make sure it is a charge we are reducing
392 unless ( $self->is_debit ) {
393 Koha::Exceptions::Account::IsNotDebit->throw(
394 error => 'Account line ' . $self->id . 'is not a debit' );
396 if ( $self->debit_type_code eq 'PAYOUT' ) {
397 Koha::Exceptions::Account::IsNotDebit->throw(
398 error => 'Account line ' . $self->id . 'is a payout' );
401 # Make sure it is not already cancelled
402 if ( $self->status && $self->status eq 'CANCELLED' ) {
403 Koha::Exceptions::Account->throw(
404 error => 'Account line ' . $self->id . 'is already cancelled' );
407 # Make sure it has not be paid yet
408 if ( $self->amount != $self->amountoutstanding ) {
409 Koha::Exceptions::Account->throw(
410 error => 'Account line ' . $self->id . 'is already offset' );
413 # Check for mandatory parameters
414 my @mandatory = ( 'staff_id', 'branch' );
415 for my $param (@mandatory) {
416 unless ( defined( $params->{$param} ) ) {
417 Koha::Exceptions::MissingParameter->throw(
418 error => "The $param parameter is mandatory" );
423 $self->_result->result_source->schema->txn_do(
426 # A 'cancellation' is a 'credit'
427 $cancellation = Koha::Account::Line->new(
430 amount => 0 - $self->amount,
431 credit_type_code => 'CANCELLATION',
433 amountoutstanding => 0 - $self->amount,
434 manager_id => $params->{staff_id},
435 borrowernumber => $self->borrowernumber,
436 interface => 'intranet',
437 branchcode => $params->{branch},
441 my $cancellation_offset = Koha::Account::Offset->new(
443 credit_id => $cancellation->accountlines_id,
445 amount => 0 - $self->amount
449 # Link cancellation to charge
450 $cancellation->apply( { debits => [$self] } );
451 $cancellation->status('APPLIED')->store();
453 # Update status of original debit
454 $self->status('CANCELLED')->store;
458 $cancellation->discard_changes;
459 return $cancellation;
464 $charge_accountline->reduce({
465 reduction_type => $reduction_type
468 Used to 'reduce' a charge/debit by adding a credit to offset against the amount
471 May be used to apply a discount whilst retaining the original debit amounts or
472 to apply a full or partial refund for example when a lost item is found and
475 It will immediately be applied to the given debit unless the debit has already
476 been paid, in which case a 'zero' offset will be added to maintain a link to
477 the debit but the outstanding credit will be left so it may be applied to other
480 Reduction type may be one of:
485 Returns the reduction accountline (which will be a credit)
490 my ( $self, $params ) = @_;
492 # Make sure it is a charge we are reducing
493 unless ( $self->is_debit ) {
494 Koha::Exceptions::Account::IsNotDebit->throw(
495 error => 'Account line ' . $self->id . 'is not a debit' );
497 if ( $self->debit_type_code eq 'PAYOUT' ) {
498 Koha::Exceptions::Account::IsNotDebit->throw(
499 error => 'Account line ' . $self->id . 'is a payout' );
502 # Check for mandatory parameters
503 my @mandatory = ( 'interface', 'reduction_type', 'amount' );
504 for my $param (@mandatory) {
505 unless ( defined( $params->{$param} ) ) {
506 Koha::Exceptions::MissingParameter->throw(
507 error => "The $param parameter is mandatory" );
511 # More mandatory parameters
512 if ( $params->{interface} eq 'intranet' ) {
513 my @optional = ( 'staff_id', 'branch' );
514 for my $param (@optional) {
515 unless ( defined( $params->{$param} ) ) {
516 Koha::Exceptions::MissingParameter->throw( error =>
517 "The $param parameter is mandatory when interface is set to 'intranet'"
523 # Make sure the reduction isn't more than the original
524 my $original = $self->amount;
525 Koha::Exceptions::Account::AmountNotPositive->throw(
526 error => 'Reduce amount passed is not positive' )
527 unless ( $params->{amount} > 0 );
528 Koha::Exceptions::ParameterTooHigh->throw( error =>
529 "Amount to reduce ($params->{amount}) is higher than original amount ($original)"
530 ) unless ( $original >= $params->{amount} );
532 $self->credits( { credit_type_code => [ 'DISCOUNT', 'REFUND' ] } )->total;
533 Koha::Exceptions::ParameterTooHigh->throw( error =>
534 "Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
537 unless ( $original >= ( $params->{amount} + abs($reduced) ) );
539 my $status = { 'REFUND' => 'REFUNDED', 'DISCOUNT' => 'DISCOUNTED' };
542 $self->_result->result_source->schema->txn_do(
545 # A 'reduction' is a 'credit'
546 $reduction = Koha::Account::Line->new(
549 amount => 0 - $params->{amount},
550 credit_type_code => $params->{reduction_type},
552 amountoutstanding => 0 - $params->{amount},
553 manager_id => $params->{staff_id},
554 borrowernumber => $self->borrowernumber,
555 interface => $params->{interface},
556 branchcode => $params->{branch},
560 my $reduction_offset = Koha::Account::Offset->new(
562 credit_id => $reduction->accountlines_id,
564 amount => 0 - $params->{amount}
568 # Link reduction to charge (and apply as required)
569 my $debit_outstanding = $self->amountoutstanding;
570 if ( $debit_outstanding >= $params->{amount} ) {
572 $reduction->apply( { debits => [$self] } );
573 $reduction->status('APPLIED')->store();
577 # Zero amount offset used to link original 'debit' to
579 my $link_reduction_offset = Koha::Account::Offset->new(
581 credit_id => $reduction->accountlines_id,
582 debit_id => $self->accountlines_id,
589 # Update status of original debit
590 $self->status( $status->{ $params->{reduction_type} } )->store;
594 $reduction->discard_changes;
600 my $debits = $account->outstanding_debits;
601 my $credit = $credit->apply( { debits => $debits } );
603 Applies the credit to a given debits array reference.
605 =head4 arguments hashref
609 =item debits - Koha::Account::Lines object set of debits
616 my ( $self, $params ) = @_;
618 my $debits = $params->{debits};
620 unless ( $self->is_credit ) {
621 Koha::Exceptions::Account::IsNotCredit->throw(
622 error => 'Account line ' . $self->id . ' is not a credit'
626 my $available_credit = $self->amountoutstanding * -1;
628 unless ( $available_credit > 0 ) {
629 Koha::Exceptions::Account::NoAvailableCredit->throw(
630 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
634 my $schema = Koha::Database->new->schema;
636 $schema->txn_do( sub {
637 for my $debit ( @{$debits} ) {
639 unless ( $debit->is_debit ) {
640 Koha::Exceptions::Account::IsNotDebit->throw(
641 error => 'Account line ' . $debit->id . 'is not a debit'
644 my $amount_to_cancel;
645 my $owed = $debit->amountoutstanding;
647 if ( $available_credit >= $owed ) {
648 $amount_to_cancel = $owed;
650 else { # $available_credit < $debit->amountoutstanding
651 $amount_to_cancel = $available_credit;
654 # record the account offset
655 Koha::Account::Offset->new(
656 { credit_id => $self->id,
657 debit_id => $debit->id,
658 amount => $amount_to_cancel * -1,
663 $available_credit -= $amount_to_cancel;
665 $self->amountoutstanding( $available_credit * -1 )->store;
666 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
668 # Attempt to renew the item associated with this debit if
670 if ( $self->credit_type_code ne 'FORGIVEN' && $debit->is_renewable ) {
671 my $outcome = $debit->renew_item( { interface => $params->{interface} } );
675 message => 'renewal',
680 $debit->discard_changes; # Refresh values from DB to clear floating point remainders
682 # Same logic exists in Koha::Account::pay
684 C4::Context->preference('MarkLostItemsAsReturned') =~
686 && $debit->debit_type_code
687 && $debit->debit_type_code eq 'LOST'
688 && $debit->amountoutstanding == 0
689 && $debit->itemnumber
691 $self->credit_type_code eq 'LOST_FOUND'
692 && $self->itemnumber == $debit->itemnumber
696 C4::Circulation::ReturnLostItem( $self->borrowernumber,
697 $debit->itemnumber );
700 last if $available_credit == 0;
709 $credit_accountline->payout(
711 payout_type => $payout_type,
712 register_id => $register_id,
713 staff_id => $staff_id,
714 interface => 'intranet',
719 Used to 'pay out' a credit to a user.
721 Payout type may be one of any existing payment types
723 Returns the payout debit line that is created via this transaction.
728 my ( $self, $params ) = @_;
730 # Make sure it is a credit we are paying out
731 unless ( $self->is_credit ) {
732 Koha::Exceptions::Account::IsNotCredit->throw(
733 error => 'Account line ' . $self->id . ' is not a credit' );
736 # Check for mandatory parameters
738 ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
739 for my $param (@mandatory) {
740 unless ( defined( $params->{$param} ) ) {
741 Koha::Exceptions::MissingParameter->throw(
742 error => "The $param parameter is mandatory" );
746 # Make sure there is outstanding credit to pay out
747 my $outstanding = -1 * $self->amountoutstanding;
749 $params->{amount} ? $params->{amount} : $outstanding;
750 Koha::Exceptions::Account::AmountNotPositive->throw(
751 error => 'Payout amount passed is not positive' )
752 unless ( $amount > 0 );
753 Koha::Exceptions::ParameterTooHigh->throw(
754 error => "Amount to payout ($amount) is higher than amountoutstanding ($outstanding)" )
755 unless ($outstanding >= $amount );
757 # Make sure we record the cash register for cash transactions
758 Koha::Exceptions::Account::RegisterRequired->throw()
759 if ( C4::Context->preference("UseCashRegisters")
760 && defined( $params->{payout_type} )
761 && ( $params->{payout_type} eq 'CASH' || $params->{payout_type} eq 'SIP00' )
762 && !defined( $params->{cash_register} ) );
765 $self->_result->result_source->schema->txn_do(
768 # A 'payout' is a 'debit'
769 $payout = Koha::Account::Line->new(
773 debit_type_code => 'PAYOUT',
774 payment_type => $params->{payout_type},
775 amountoutstanding => $amount,
776 manager_id => $params->{staff_id},
777 borrowernumber => $self->borrowernumber,
778 interface => $params->{interface},
779 branchcode => $params->{branch},
780 register_id => $params->{cash_register}
784 my $payout_offset = Koha::Account::Offset->new(
786 debit_id => $payout->accountlines_id,
792 $self->apply( { debits => [$payout] } );
793 $self->status('PAID')->store;
797 $payout->discard_changes;
803 This method allows updating a debit or credit on a patron's account
805 $account_line->adjust(
808 type => $update_type,
809 interface => $interface
813 $update_type can be any of:
816 Authors Note: The intention here is that this method is only used
817 to adjust accountlines where the final amount is not yet known/fixed.
818 Incrementing fines are the only existing case at the time of writing,
819 all other forms of 'adjustment' should be recorded as distinct credits
820 or debits and applied, via an offset, to the corresponding debit or credit.
825 my ( $self, $params ) = @_;
827 my $amount = $params->{amount};
828 my $update_type = $params->{type};
829 my $interface = $params->{interface};
831 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
832 Koha::Exceptions::Account::UnrecognisedType->throw(
833 error => 'Update type not recognised'
837 my $debit_type_code = $self->debit_type_code;
838 my $account_status = $self->status;
842 $Koha::Account::Line::allowed_update->{$update_type}
845 && ( $Koha::Account::Line::allowed_update->{$update_type}
846 ->{$debit_type_code} eq $account_status )
850 Koha::Exceptions::Account::UnrecognisedType->throw(
851 error => 'Update type not allowed on this debit_type' );
854 my $schema = Koha::Database->new->schema;
859 my $amount_before = $self->amount;
860 my $amount_outstanding_before = $self->amountoutstanding;
861 my $difference = $amount - $amount_before;
862 my $new_outstanding = $amount_outstanding_before + $difference;
864 my $offset_type = $debit_type_code;
865 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
867 # Catch cases that require patron refunds
868 if ( $new_outstanding < 0 ) {
870 Koha::Patrons->find( $self->borrowernumber )->account;
871 my $credit = $account->add_credit(
873 amount => $new_outstanding * -1,
874 type => 'OVERPAYMENT',
875 interface => $interface,
876 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
879 $new_outstanding = 0;
882 # Update the account line
887 amountoutstanding => $new_outstanding,
891 # Record the account offset
892 my $account_offset = Koha::Account::Offset->new(
894 debit_id => $self->id,
895 type => $offset_type,
896 amount => $difference
900 if ( C4::Context->preference("FinesLog") ) {
902 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
903 $self->borrowernumber,
905 { action => $update_type,
906 borrowernumber => $self->borrowernumber,
908 description => undef,
909 amountoutstanding => $new_outstanding,
910 debit_type_code => $self->debit_type_code,
912 itemnumber => $self->itemnumber,
916 ) if ( $update_type eq 'overdue_update' );
926 my $bool = $line->is_credit;
933 return defined $self->credit_type_code;
938 my $bool = $line->is_debit;
945 return !$self->is_credit;
948 =head3 to_api_mapping
950 This method returns the mapping for representing a Koha::Account::Line object
957 accountlines_id => 'account_line_id',
958 credit_number => undef,
959 credit_type_code => 'credit_type',
960 debit_type_code => 'debit_type',
961 amountoutstanding => 'amount_outstanding',
962 borrowernumber => 'patron_id',
963 branchcode => 'library_id',
964 issue_id => 'checkout_id',
965 itemnumber => 'item_id',
966 manager_id => 'user_id',
967 note => 'internal_note',
968 register_id => 'cash_register_id',
975 my $bool = $line->is_renewable;
983 $self->amountoutstanding == 0 &&
984 $self->debit_type_code &&
985 $self->debit_type_code eq 'OVERDUE' &&
987 $self->status eq 'UNRETURNED' &&
995 my $renew_result = $line->renew_item;
997 Conditionally attempt to renew an item and return the outcome. This is
998 as a consequence of the fine on an item being fully paid off.
999 Caller must call is_renewable before.
1004 my ($self, $params) = @_;
1008 # We want to reject the call to renew if:
1009 # - The RenewAccruingItemWhenPaid syspref is off
1011 # - The RenewAccruingItemInOpac syspref is off
1012 # - There is an interface param passed and it's value is 'opac'
1015 !C4::Context->preference('RenewAccruingItemWhenPaid') ||
1017 !C4::Context->preference('RenewAccruingItemInOpac') &&
1018 $params->{interface} &&
1019 $params->{interface} eq 'opac'
1025 my $itemnumber = $self->item->itemnumber;
1026 my $borrowernumber = $self->patron->borrowernumber;
1027 my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1032 my $due_date = C4::Circulation::AddRenewal(
1035 $self->{branchcode},
1041 itemnumber => $itemnumber,
1042 due_date => $due_date,
1047 itemnumber => $itemnumber,
1057 Specific store method to generate credit number before saving
1064 my $AutoCreditNumber = C4::Context->preference('AutoCreditNumber');
1065 my $credit_number_enabled = $self->is_credit && $self->credit_type->credit_number_enabled;
1067 if ($AutoCreditNumber && $credit_number_enabled && !$self->in_storage) {
1068 if (defined $self->credit_number) {
1069 Koha::Exceptions::Account->throw('AutoCreditNumber is enabled but credit_number is already defined');
1072 my $rs = Koha::Database->new->schema->resultset($self->_type);
1074 if ($AutoCreditNumber eq 'incremental') {
1075 my $max = $rs->search({
1076 credit_number => { -regexp => '^[0-9]+$' }
1078 select => \'CAST(credit_number AS UNSIGNED)',
1079 as => ['credit_number'],
1080 })->get_column('credit_number')->max;
1082 $self->credit_number($max + 1);
1083 } elsif ($AutoCreditNumber eq 'annual') {
1084 my $now = dt_from_string;
1085 my $prefix = sprintf('%d-', $now->year);
1086 my $max = $rs->search({
1088 credit_number => { -regexp => '[0-9]{4}$' },
1089 credit_number => { -like => "$prefix%" },
1091 })->get_column('credit_number')->max;
1092 $max //= $prefix . '0000';
1093 my $incr = substr($max, length $prefix);
1094 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1095 } elsif ($AutoCreditNumber eq 'branchyyyymmincr') {
1096 my $userenv = C4::Context->userenv;
1098 my $branch = $userenv->{branch};
1099 my $now = dt_from_string;
1100 my $prefix = sprintf('%s%d%02d', $branch, $now->year, $now->month);
1101 my $pattern = $prefix;
1102 $pattern =~ s/([\?%_])/\\$1/g;
1103 my $max = $rs->search({
1105 credit_number => { -regexp => '[0-9]{4}$' },
1106 credit_number => { -like => "$pattern%" },
1108 })->get_column('credit_number')->max;
1109 $max //= $prefix . '0000';
1110 my $incr = substr($max, length $prefix);
1111 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1116 return $self->SUPER::store();
1119 =head2 Internal methods
1128 return 'Accountline';
1133 =head2 Name mappings
1135 =head3 $allowed_update
1139 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
1143 Kyle M Hall <kyle@bywatersolutions.com >
1144 Tomás Cohen Arazi <tomascohen@theke.io>
1145 Martin Renvoize <martin.renvoize@ptfs-europe.com>