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 return Koha::Checkouts->find( $self->issue_id )
97 || Koha::Old::Checkouts->find( $self->issue_id );
102 Returns a Koha::Library object representing where the accountline was recorded
108 my $rs = $self->_result->library;
110 return Koha::Library->_new_from_dbic($rs);
115 Return the credit_type linked to this account line
121 my $rs = $self->_result->credit_type_code;
123 return Koha::Account::CreditType->_new_from_dbic( $rs );
128 Return the debit_type linked to this account line
134 my $rs = $self->_result->debit_type_code;
136 return Koha::Account::DebitType->_new_from_dbic( $rs );
139 =head3 credit_offsets
141 Return the credit_offsets linked to this account line if some exist
146 my ( $self, $cond, $attr ) = @_;
148 unless ( $self->is_credit ) {
149 Koha::Exceptions::Account::IsNotCredit->throw(
150 error => 'Account line ' . $self->id . ' is not a credit'
154 my $rs = $self->_result->search_related( 'account_offsets_credits', $cond, $attr);
156 return Koha::Account::Offsets->_new_from_dbic($rs);
161 Return the debit_offsets linked to this account line if some exist
166 my ( $self, $cond, $attr ) = @_;
168 unless ( $self->is_debit ) {
169 Koha::Exceptions::Account::IsNotDebit->throw(
170 error => 'Account line ' . $self->id . ' is not a debit'
174 my $rs = $self->_result->search_related( 'account_offsets_debits', $cond, $attr);
176 return Koha::Account::Offsets->_new_from_dbic($rs);
181 my $credits = $accountline->credits;
182 my $credits = $accountline->credits( $cond, $attr );
184 Return the credits linked to this account line if some exist.
185 Search conditions and attributes may be passed if you wish to filter
186 the resultant resultant resultset.
191 my ( $self, $cond, $attr ) = @_;
193 unless ( $self->is_debit ) {
194 Koha::Exceptions::Account::IsNotDebit->throw(
195 error => 'Account line ' . $self->id . ' is not a debit'
199 my $cond_m = { map { "credit.".$_ => $cond->{$_} } keys %{$cond}};
201 $self->_result->search_related('account_offsets_debits')
202 ->search_related( 'credit', $cond_m, $attr );
204 return Koha::Account::Lines->_new_from_dbic($rs);
209 my $debits = $accountline->debits;
210 my $debits = $accountline->debits( $cond, $attr );
212 Return the debits linked to this account line if some exist.
213 Search conditions and attributes may be passed if you wish to filter
214 the resultant resultant resultset.
219 my ( $self, $cond, $attr ) = @_;
221 unless ( $self->is_credit ) {
222 Koha::Exceptions::Account::IsNotCredit->throw(
223 error => 'Account line ' . $self->id . ' is not a credit'
227 my $cond_m = { map { "debit.".$_ => $cond->{$_} } keys %{$cond}};
229 $self->_result->search_related('account_offsets_credits')
230 ->search_related( 'debit', $cond_m, $attr );
232 return Koha::Account::Lines->_new_from_dbic($rs);
237 $payment_accountline->void({
238 interface => $interface,
239 [ staff_id => $staff_id, branch => $branchcode ]
242 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
243 created by the application of this credit upon any debits and mark the credit
244 as 'void' by updating it's status to "VOID".
249 my ($self, $params) = @_;
251 # Make sure it is a credit we are voiding
252 unless ( $self->is_credit ) {
253 Koha::Exceptions::Account::IsNotCredit->throw(
254 error => 'Account line ' . $self->id . 'is not a credit' );
257 # Make sure it is not already voided
258 if ( $self->status && $self->status eq 'VOID' ) {
259 Koha::Exceptions::Account->throw(
260 error => 'Account line ' . $self->id . 'is already void' );
263 # Check for mandatory parameters
264 my @mandatory = ( 'interface' );
265 for my $param (@mandatory) {
266 unless ( defined( $params->{$param} ) ) {
267 Koha::Exceptions::MissingParameter->throw(
268 error => "The $param parameter is mandatory" );
272 # More mandatory parameters
273 if ( $params->{interface} eq 'intranet' ) {
274 my @optional = ( 'staff_id', 'branch' );
275 for my $param (@optional) {
276 unless ( defined( $params->{$param} ) ) {
277 Koha::Exceptions::MissingParameter->throw( error =>
278 "The $param parameter is mandatory when interface is set to 'intranet'"
284 # Find any applied offsets for the credit so we may reverse them
285 my @account_offsets =
286 Koha::Account::Offsets->search(
287 { credit_id => $self->id, amount => { '<' => 0 } } )->as_list;
290 $self->_result->result_source->schema->txn_do(
293 # A 'void' is a 'debit'
294 $void = Koha::Account::Line->new(
296 borrowernumber => $self->borrowernumber,
298 debit_type_code => 'VOID',
299 amount => $self->amount * -1,
300 amountoutstanding => $self->amount * -1,
301 manager_id => $params->{staff_id},
302 interface => $params->{interface},
303 branchcode => $params->{branch},
307 # Record the creation offset
308 Koha::Account::Offset->new(
310 debit_id => $void->id,
312 amount => $self->amount * -1
316 # Link void to payment
318 amountoutstanding => $self->amount,
321 $self->apply( { debits => [$void] } );
323 # Reverse any applied payments
324 foreach my $account_offset (@account_offsets) {
326 Koha::Account::Lines->find( $account_offset->debit_id );
328 next unless $fee_paid;
330 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
331 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
332 $fee_paid->amountoutstanding($new_amount);
335 Koha::Account::Offset->new(
337 credit_id => $self->id,
338 debit_id => $fee_paid->id,
339 amount => $amount_paid,
345 if ( C4::Context->preference("FinesLog") ) {
348 $self->borrowernumber,
351 action => 'void_payment',
352 borrowernumber => $self->borrowernumber,
353 amount => $self->amount,
354 amountoutstanding => $self->amountoutstanding,
355 description => $self->description,
356 credit_type_code => $self->credit_type_code,
357 payment_type => $self->payment_type,
359 itemnumber => $self->itemnumber,
360 manager_id => $self->manager_id,
362 [ map { $_->unblessed } @account_offsets ],
370 $void->discard_changes;
376 $debit_accountline->cancel();
378 Cancel a charge. It will mark the debit as 'cancelled' by updating its
379 status to 'CANCELLED'.
381 Charges that have been fully or partially paid cannot be cancelled.
383 Returns the cancellation accountline.
388 my ( $self, $params ) = @_;
390 # Make sure it is a charge we are reducing
391 unless ( $self->is_debit ) {
392 Koha::Exceptions::Account::IsNotDebit->throw(
393 error => 'Account line ' . $self->id . 'is not a debit' );
395 if ( $self->debit_type_code eq 'PAYOUT' ) {
396 Koha::Exceptions::Account::IsNotDebit->throw(
397 error => 'Account line ' . $self->id . 'is a payout' );
400 # Make sure it is not already cancelled
401 if ( $self->status && $self->status eq 'CANCELLED' ) {
402 Koha::Exceptions::Account->throw(
403 error => 'Account line ' . $self->id . 'is already cancelled' );
406 # Make sure it has not be paid yet
407 if ( $self->amount != $self->amountoutstanding ) {
408 Koha::Exceptions::Account->throw(
409 error => 'Account line ' . $self->id . 'is already offset' );
412 # Check for mandatory parameters
413 my @mandatory = ( 'staff_id', 'branch' );
414 for my $param (@mandatory) {
415 unless ( defined( $params->{$param} ) ) {
416 Koha::Exceptions::MissingParameter->throw(
417 error => "The $param parameter is mandatory" );
422 $self->_result->result_source->schema->txn_do(
425 # A 'cancellation' is a 'credit'
426 $cancellation = Koha::Account::Line->new(
429 amount => 0 - $self->amount,
430 credit_type_code => 'CANCELLATION',
432 amountoutstanding => 0 - $self->amount,
433 manager_id => $params->{staff_id},
434 borrowernumber => $self->borrowernumber,
435 interface => 'intranet',
436 branchcode => $params->{branch},
440 my $cancellation_offset = Koha::Account::Offset->new(
442 credit_id => $cancellation->accountlines_id,
444 amount => 0 - $self->amount
448 # Link cancellation to charge
449 $cancellation->apply( { debits => [$self] } );
450 $cancellation->status('APPLIED')->store();
452 # Update status of original debit
453 $self->status('CANCELLED')->store;
457 $cancellation->discard_changes;
458 return $cancellation;
463 $charge_accountline->reduce({
464 reduction_type => $reduction_type
467 Used to 'reduce' a charge/debit by adding a credit to offset against the amount
470 May be used to apply a discount whilst retaining the original debit amounts or
471 to apply a full or partial refund for example when a lost item is found and
474 It will immediately be applied to the given debit unless the debit has already
475 been paid, in which case a 'zero' offset will be added to maintain a link to
476 the debit but the outstanding credit will be left so it may be applied to other
479 Reduction type may be one of:
484 Returns the reduction accountline (which will be a credit)
489 my ( $self, $params ) = @_;
491 # Make sure it is a charge we are reducing
492 unless ( $self->is_debit ) {
493 Koha::Exceptions::Account::IsNotDebit->throw(
494 error => 'Account line ' . $self->id . 'is not a debit' );
496 if ( $self->debit_type_code eq 'PAYOUT' ) {
497 Koha::Exceptions::Account::IsNotDebit->throw(
498 error => 'Account line ' . $self->id . 'is a payout' );
501 # Check for mandatory parameters
502 my @mandatory = ( 'interface', 'reduction_type', 'amount' );
503 for my $param (@mandatory) {
504 unless ( defined( $params->{$param} ) ) {
505 Koha::Exceptions::MissingParameter->throw(
506 error => "The $param parameter is mandatory" );
510 # More mandatory parameters
511 if ( $params->{interface} eq 'intranet' ) {
512 my @optional = ( 'staff_id', 'branch' );
513 for my $param (@optional) {
514 unless ( defined( $params->{$param} ) ) {
515 Koha::Exceptions::MissingParameter->throw( error =>
516 "The $param parameter is mandatory when interface is set to 'intranet'"
522 # Make sure the reduction isn't more than the original
523 my $original = $self->amount;
524 Koha::Exceptions::Account::AmountNotPositive->throw(
525 error => 'Reduce amount passed is not positive' )
526 unless ( $params->{amount} > 0 );
527 Koha::Exceptions::ParameterTooHigh->throw( error =>
528 "Amount to reduce ($params->{amount}) is higher than original amount ($original)"
529 ) unless ( $original >= $params->{amount} );
531 $self->credits( { credit_type_code => [ 'DISCOUNT', 'REFUND' ] } )->total;
532 Koha::Exceptions::ParameterTooHigh->throw( error =>
533 "Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
536 unless ( $original >= ( $params->{amount} + abs($reduced) ) );
538 my $status = { 'REFUND' => 'REFUNDED', 'DISCOUNT' => 'DISCOUNTED' };
541 $self->_result->result_source->schema->txn_do(
544 # A 'reduction' is a 'credit'
545 $reduction = Koha::Account::Line->new(
548 amount => 0 - $params->{amount},
549 credit_type_code => $params->{reduction_type},
551 amountoutstanding => 0 - $params->{amount},
552 manager_id => $params->{staff_id},
553 borrowernumber => $self->borrowernumber,
554 interface => $params->{interface},
555 branchcode => $params->{branch},
559 my $reduction_offset = Koha::Account::Offset->new(
561 credit_id => $reduction->accountlines_id,
563 amount => 0 - $params->{amount}
567 # Link reduction to charge (and apply as required)
568 my $debit_outstanding = $self->amountoutstanding;
569 if ( $debit_outstanding >= $params->{amount} ) {
571 $reduction->apply( { debits => [$self] } );
572 $reduction->status('APPLIED')->store();
576 # Zero amount offset used to link original 'debit' to
578 my $link_reduction_offset = Koha::Account::Offset->new(
580 credit_id => $reduction->accountlines_id,
581 debit_id => $self->accountlines_id,
588 # Update status of original debit
589 $self->status( $status->{ $params->{reduction_type} } )->store;
593 $reduction->discard_changes;
599 my $debits = $account->outstanding_debits;
600 my $credit = $credit->apply( { debits => $debits } );
602 Applies the credit to a given debits array reference.
604 =head4 arguments hashref
608 =item debits - Koha::Account::Lines object set of debits
615 my ( $self, $params ) = @_;
617 my $debits = $params->{debits};
619 unless ( $self->is_credit ) {
620 Koha::Exceptions::Account::IsNotCredit->throw(
621 error => 'Account line ' . $self->id . ' is not a credit'
625 my $available_credit = $self->amountoutstanding * -1;
627 unless ( $available_credit > 0 ) {
628 Koha::Exceptions::Account::NoAvailableCredit->throw(
629 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
633 my $schema = Koha::Database->new->schema;
635 $schema->txn_do( sub {
636 for my $debit ( @{$debits} ) {
638 unless ( $debit->is_debit ) {
639 Koha::Exceptions::Account::IsNotDebit->throw(
640 error => 'Account line ' . $debit->id . 'is not a debit'
643 my $amount_to_cancel;
644 my $owed = $debit->amountoutstanding;
646 if ( $available_credit >= $owed ) {
647 $amount_to_cancel = $owed;
649 else { # $available_credit < $debit->amountoutstanding
650 $amount_to_cancel = $available_credit;
653 # record the account offset
654 Koha::Account::Offset->new(
655 { credit_id => $self->id,
656 debit_id => $debit->id,
657 amount => $amount_to_cancel * -1,
662 $available_credit -= $amount_to_cancel;
664 $self->amountoutstanding( $available_credit * -1 )->store;
665 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
667 # Attempt to renew the item associated with this debit if
669 if ( $self->credit_type_code ne 'FORGIVEN' && $debit->is_renewable ) {
670 my $outcome = $debit->renew_item( { interface => $params->{interface} } );
674 message => 'renewal',
679 $debit->discard_changes; # Refresh values from DB to clear floating point remainders
681 # Same logic exists in Koha::Account::pay
683 C4::Context->preference('MarkLostItemsAsReturned') =~
685 && $debit->debit_type_code
686 && $debit->debit_type_code eq 'LOST'
687 && $debit->amountoutstanding == 0
688 && $debit->itemnumber
690 $self->credit_type_code eq 'LOST_FOUND'
691 && $self->itemnumber == $debit->itemnumber
695 C4::Circulation::ReturnLostItem( $self->borrowernumber,
696 $debit->itemnumber );
699 last if $available_credit == 0;
708 $credit_accountline->payout(
710 payout_type => $payout_type,
711 register_id => $register_id,
712 staff_id => $staff_id,
713 interface => 'intranet',
718 Used to 'pay out' a credit to a user.
720 Payout type may be one of any existing payment types
722 Returns the payout debit line that is created via this transaction.
727 my ( $self, $params ) = @_;
729 # Make sure it is a credit we are paying out
730 unless ( $self->is_credit ) {
731 Koha::Exceptions::Account::IsNotCredit->throw(
732 error => 'Account line ' . $self->id . ' is not a credit' );
735 # Check for mandatory parameters
737 ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
738 for my $param (@mandatory) {
739 unless ( defined( $params->{$param} ) ) {
740 Koha::Exceptions::MissingParameter->throw(
741 error => "The $param parameter is mandatory" );
745 # Make sure there is outstanding credit to pay out
746 my $outstanding = -1 * $self->amountoutstanding;
748 $params->{amount} ? $params->{amount} : $outstanding;
749 Koha::Exceptions::Account::AmountNotPositive->throw(
750 error => 'Payout amount passed is not positive' )
751 unless ( $amount > 0 );
752 Koha::Exceptions::ParameterTooHigh->throw(
753 error => "Amount to payout ($amount) is higher than amountoutstanding ($outstanding)" )
754 unless ($outstanding >= $amount );
756 # Make sure we record the cash register for cash transactions
757 Koha::Exceptions::Account::RegisterRequired->throw()
758 if ( C4::Context->preference("UseCashRegisters")
759 && defined( $params->{payout_type} )
760 && ( $params->{payout_type} eq 'CASH' || $params->{payout_type} eq 'SIP00' )
761 && !defined( $params->{cash_register} ) );
764 $self->_result->result_source->schema->txn_do(
767 # A 'payout' is a 'debit'
768 $payout = Koha::Account::Line->new(
772 debit_type_code => 'PAYOUT',
773 payment_type => $params->{payout_type},
774 amountoutstanding => $amount,
775 manager_id => $params->{staff_id},
776 borrowernumber => $self->borrowernumber,
777 interface => $params->{interface},
778 branchcode => $params->{branch},
779 register_id => $params->{cash_register}
783 my $payout_offset = Koha::Account::Offset->new(
785 debit_id => $payout->accountlines_id,
791 $self->apply( { debits => [$payout] } );
792 $self->status('PAID')->store;
796 $payout->discard_changes;
802 This method allows updating a debit or credit on a patron's account
804 $account_line->adjust(
807 type => $update_type,
808 interface => $interface
812 $update_type can be any of:
815 Authors Note: The intention here is that this method is only used
816 to adjust accountlines where the final amount is not yet known/fixed.
817 Incrementing fines are the only existing case at the time of writing,
818 all other forms of 'adjustment' should be recorded as distinct credits
819 or debits and applied, via an offset, to the corresponding debit or credit.
824 my ( $self, $params ) = @_;
826 my $amount = $params->{amount};
827 my $update_type = $params->{type};
828 my $interface = $params->{interface};
830 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
831 Koha::Exceptions::Account::UnrecognisedType->throw(
832 error => 'Update type not recognised'
836 my $debit_type_code = $self->debit_type_code;
837 my $account_status = $self->status;
841 $Koha::Account::Line::allowed_update->{$update_type}
844 && ( $Koha::Account::Line::allowed_update->{$update_type}
845 ->{$debit_type_code} eq $account_status )
849 Koha::Exceptions::Account::UnrecognisedType->throw(
850 error => 'Update type not allowed on this debit_type' );
853 my $schema = Koha::Database->new->schema;
858 my $amount_before = $self->amount;
859 my $amount_outstanding_before = $self->amountoutstanding;
860 my $difference = $amount - $amount_before;
861 my $new_outstanding = $amount_outstanding_before + $difference;
863 my $offset_type = $debit_type_code;
864 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
866 # Catch cases that require patron refunds
867 if ( $new_outstanding < 0 ) {
869 Koha::Patrons->find( $self->borrowernumber )->account;
870 my $credit = $account->add_credit(
872 amount => $new_outstanding * -1,
873 type => 'OVERPAYMENT',
874 interface => $interface,
875 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
878 $new_outstanding = 0;
881 # Update the account line
886 amountoutstanding => $new_outstanding,
890 # Record the account offset
891 my $account_offset = Koha::Account::Offset->new(
893 debit_id => $self->id,
894 type => $offset_type,
895 amount => $difference
899 if ( C4::Context->preference("FinesLog") ) {
901 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
902 $self->borrowernumber,
904 { action => $update_type,
905 borrowernumber => $self->borrowernumber,
907 description => undef,
908 amountoutstanding => $new_outstanding,
909 debit_type_code => $self->debit_type_code,
911 itemnumber => $self->itemnumber,
915 ) if ( $update_type eq 'overdue_update' );
925 my $bool = $line->is_credit;
932 return defined $self->credit_type_code;
937 my $bool = $line->is_debit;
944 return !$self->is_credit;
947 =head3 to_api_mapping
949 This method returns the mapping for representing a Koha::Account::Line object
956 accountlines_id => 'account_line_id',
957 credit_number => undef,
958 credit_type_code => 'credit_type',
959 debit_type_code => 'debit_type',
960 amountoutstanding => 'amount_outstanding',
961 borrowernumber => 'patron_id',
962 branchcode => 'library_id',
963 issue_id => 'checkout_id',
964 itemnumber => 'item_id',
965 manager_id => 'user_id',
966 note => 'internal_note',
967 register_id => 'cash_register_id',
974 my $bool = $line->is_renewable;
982 $self->amountoutstanding == 0 &&
983 $self->debit_type_code &&
984 $self->debit_type_code eq 'OVERDUE' &&
986 $self->status eq 'UNRETURNED' &&
994 my $renew_result = $line->renew_item;
996 Conditionally attempt to renew an item and return the outcome. This is
997 as a consequence of the fine on an item being fully paid off.
998 Caller must call is_renewable before.
1003 my ($self, $params) = @_;
1007 # We want to reject the call to renew if:
1008 # - The RenewAccruingItemWhenPaid syspref is off
1010 # - The RenewAccruingItemInOpac syspref is off
1011 # - There is an interface param passed and it's value is 'opac'
1014 !C4::Context->preference('RenewAccruingItemWhenPaid') ||
1016 !C4::Context->preference('RenewAccruingItemInOpac') &&
1017 $params->{interface} &&
1018 $params->{interface} eq 'opac'
1024 my $itemnumber = $self->item->itemnumber;
1025 my $borrowernumber = $self->patron->borrowernumber;
1026 my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1031 my $due_date = C4::Circulation::AddRenewal(
1034 $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>