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);
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 item linked to this account line if exists
68 my $rs = $self->_result->itemnumber;
70 return Koha::Item->_new_from_dbic( $rs );
75 Return the checkout linked to this account line if exists
81 return unless $self->issue_id ;
83 $self->{_checkout} ||= Koha::Checkouts->find( $self->issue_id );
84 $self->{_checkout} ||= Koha::Old::Checkouts->find( $self->issue_id );
85 return $self->{_checkout};
90 Returns a Koha::Library object representing where the accountline was recorded
96 my $rs = $self->_result->library;
98 return Koha::Library->_new_from_dbic($rs);
103 Return the credit_type linked to this account line
109 my $rs = $self->_result->credit_type_code;
111 return Koha::Account::CreditType->_new_from_dbic( $rs );
116 Return the debit_type linked to this account line
122 my $rs = $self->_result->debit_type_code;
124 return Koha::Account::DebitType->_new_from_dbic( $rs );
127 =head3 credit_offsets
129 Return the credit_offsets linked to this account line if some exist
135 my $rs = $self->_result->account_offsets_credits;
137 return Koha::Account::Offsets->_new_from_dbic($rs);
142 Return the debit_offsets linked to this account line if some exist
148 my $rs = $self->_result->account_offsets_debits;
150 return Koha::Account::Offsets->_new_from_dbic($rs);
156 my $credits = $accountline->credits;
157 my $credits = $accountline->credits( $cond, $attr );
159 Return the credits linked to this account line if some exist.
160 Search conditions and attributes may be passed if you wish to filter
161 the resultant resultant resultset.
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 $cond_m = { map { "credit.".$_ => $cond->{$_} } keys %{$cond}};
176 $self->_result->search_related('account_offsets_debits')
177 ->search_related( 'credit', $cond_m, $attr );
179 return Koha::Account::Lines->_new_from_dbic($rs);
184 my $debits = $accountline->debits;
185 my $debits = $accountline->debits( $cond, $attr );
187 Return the debits linked to this account line if some exist.
188 Search conditions and attributes may be passed if you wish to filter
189 the resultant resultant resultset.
194 my ( $self, $cond, $attr ) = @_;
196 unless ( $self->is_credit ) {
197 Koha::Exceptions::Account::IsNotCredit->throw(
198 error => 'Account line ' . $self->id . ' is not a credit'
202 my $cond_m = { map { "debit.".$_ => $cond->{$_} } keys %{$cond}};
204 $self->_result->search_related('account_offsets_credits')
205 ->search_related( 'debit', $cond_m, $attr );
207 return Koha::Account::Lines->_new_from_dbic($rs);
212 $payment_accountline->void({
213 interface => $interface,
214 [ staff_id => $staff_id, branch => $branchcode ]
217 Used to 'void' (or reverse) a payment/credit. It will roll back any offsets
218 created by the application of this credit upon any debits and mark the credit
219 as 'void' by updating it's status to "VOID".
224 my ($self, $params) = @_;
226 # Make sure it is a credit we are voiding
227 unless ( $self->is_credit ) {
228 Koha::Exceptions::Account::IsNotCredit->throw(
229 error => 'Account line ' . $self->id . 'is not a credit' );
232 # Make sure it is not already voided
233 if ( $self->status && $self->status eq 'VOID' ) {
234 Koha::Exceptions::Account->throw(
235 error => 'Account line ' . $self->id . 'is already void' );
238 # Check for mandatory parameters
239 my @mandatory = ( 'interface' );
240 for my $param (@mandatory) {
241 unless ( defined( $params->{$param} ) ) {
242 Koha::Exceptions::MissingParameter->throw(
243 error => "The $param parameter is mandatory" );
247 # More mandatory parameters
248 if ( $params->{interface} eq 'intranet' ) {
249 my @optional = ( 'staff_id', 'branch' );
250 for my $param (@optional) {
251 unless ( defined( $params->{$param} ) ) {
252 Koha::Exceptions::MissingParameter->throw( error =>
253 "The $param parameter is mandatory when interface is set to 'intranet'"
259 # Find any applied offsets for the credit so we may reverse them
260 my @account_offsets =
261 Koha::Account::Offsets->search(
262 { credit_id => $self->id, amount => { '<' => 0 } } );
265 $self->_result->result_source->schema->txn_do(
268 # A 'void' is a 'debit'
269 $void = Koha::Account::Line->new(
271 borrowernumber => $self->borrowernumber,
273 debit_type_code => 'VOID',
274 amount => $self->amount * -1,
275 amountoutstanding => $self->amount * -1,
276 manager_id => $params->{staff_id},
277 interface => $params->{interface},
278 branchcode => $params->{branch},
282 # Record the creation offset
283 Koha::Account::Offset->new(
285 debit_id => $void->id,
287 amount => $self->amount * -1
291 # Reverse any applied payments
292 foreach my $account_offset (@account_offsets) {
294 Koha::Account::Lines->find( $account_offset->debit_id );
296 next unless $fee_paid;
298 my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount
299 my $new_amount = $fee_paid->amountoutstanding + $amount_paid;
300 $fee_paid->amountoutstanding($new_amount);
303 Koha::Account::Offset->new(
305 credit_id => $self->id,
306 debit_id => $fee_paid->id,
307 amount => $amount_paid,
313 # Link void to payment
315 amountoutstanding => $self->amount,
318 $self->apply({ debits => [$void]});
320 if ( C4::Context->preference("FinesLog") ) {
323 $self->borrowernumber,
326 action => 'void_payment',
327 borrowernumber => $self->borrowernumber,
328 amount => $self->amount,
329 amountoutstanding => $self->amountoutstanding,
330 description => $self->description,
331 credit_type_code => $self->credit_type_code,
332 payment_type => $self->payment_type,
334 itemnumber => $self->itemnumber,
335 manager_id => $self->manager_id,
337 [ map { $_->unblessed } @account_offsets ],
345 $void->discard_changes;
351 $debit_accountline->cancel();
353 Cancel a charge. It will mark the debit as 'cancelled' by updating its
354 status to 'CANCELLED'.
356 Charges that have been fully or partially paid cannot be cancelled.
358 Returns the cancellation accountline.
363 my ( $self, $params ) = @_;
365 # Make sure it is a charge we are reducing
366 unless ( $self->is_debit ) {
367 Koha::Exceptions::Account::IsNotDebit->throw(
368 error => 'Account line ' . $self->id . 'is not a debit' );
370 if ( $self->debit_type_code eq 'PAYOUT' ) {
371 Koha::Exceptions::Account::IsNotDebit->throw(
372 error => 'Account line ' . $self->id . 'is a payout' );
375 # Make sure it is not already cancelled
376 if ( $self->status && $self->status eq 'CANCELLED' ) {
377 Koha::Exceptions::Account->throw(
378 error => 'Account line ' . $self->id . 'is already cancelled' );
381 # Make sure it has not be paid yet
382 if ( $self->amount != $self->amountoutstanding ) {
383 Koha::Exceptions::Account->throw(
384 error => 'Account line ' . $self->id . 'is already offset' );
387 # Check for mandatory parameters
388 my @mandatory = ( 'staff_id', 'branch' );
389 for my $param (@mandatory) {
390 unless ( defined( $params->{$param} ) ) {
391 Koha::Exceptions::MissingParameter->throw(
392 error => "The $param parameter is mandatory" );
397 $self->_result->result_source->schema->txn_do(
400 # A 'cancellation' is a 'credit'
401 $cancellation = Koha::Account::Line->new(
404 amount => 0 - $self->amount,
405 credit_type_code => 'CANCELLATION',
407 amountoutstanding => 0 - $self->amount,
408 manager_id => $params->{staff_id},
409 borrowernumber => $self->borrowernumber,
410 interface => 'intranet',
411 branchcode => $params->{branch},
415 my $cancellation_offset = Koha::Account::Offset->new(
417 credit_id => $cancellation->accountlines_id,
418 type => 'CANCELLATION',
419 amount => $self->amount
423 # Link cancellation to charge
424 $cancellation->apply(
427 offset_type => 'CANCELLATION'
430 $cancellation->status('APPLIED')->store();
432 # Update status of original debit
433 $self->status('CANCELLED')->store;
437 $cancellation->discard_changes;
438 return $cancellation;
443 $charge_accountline->reduce({
444 reduction_type => $reduction_type
447 Used to 'reduce' a charge/debit by adding a credit to offset against the amount
450 May be used to apply a discount whilst retaining the original debit amounts or
451 to apply a full or partial refund for example when a lost item is found and
454 It will immediately be applied to the given debit unless the debit has already
455 been paid, in which case a 'zero' offset will be added to maintain a link to
456 the debit but the outstanding credit will be left so it may be applied to other
459 Reduction type may be one of:
464 Returns the reduction accountline (which will be a credit)
469 my ( $self, $params ) = @_;
471 # Make sure it is a charge we are reducing
472 unless ( $self->is_debit ) {
473 Koha::Exceptions::Account::IsNotDebit->throw(
474 error => 'Account line ' . $self->id . 'is not a debit' );
476 if ( $self->debit_type_code eq 'PAYOUT' ) {
477 Koha::Exceptions::Account::IsNotDebit->throw(
478 error => 'Account line ' . $self->id . 'is a payout' );
481 # Check for mandatory parameters
482 my @mandatory = ( 'interface', 'reduction_type', 'amount' );
483 for my $param (@mandatory) {
484 unless ( defined( $params->{$param} ) ) {
485 Koha::Exceptions::MissingParameter->throw(
486 error => "The $param parameter is mandatory" );
490 # More mandatory parameters
491 if ( $params->{interface} eq 'intranet' ) {
492 my @optional = ( 'staff_id', 'branch' );
493 for my $param (@optional) {
494 unless ( defined( $params->{$param} ) ) {
495 Koha::Exceptions::MissingParameter->throw( error =>
496 "The $param parameter is mandatory when interface is set to 'intranet'"
502 # Make sure the reduction isn't more than the original
503 my $original = $self->amount;
504 Koha::Exceptions::Account::AmountNotPositive->throw(
505 error => 'Reduce amount passed is not positive' )
506 unless ( $params->{amount} > 0 );
507 Koha::Exceptions::ParameterTooHigh->throw( error =>
508 "Amount to reduce ($params->{amount}) is higher than original amount ($original)"
509 ) unless ( $original >= $params->{amount} );
511 $self->credits( { credit_type_code => [ 'DISCOUNT', 'REFUND' ] } )->total;
512 Koha::Exceptions::ParameterTooHigh->throw( error =>
513 "Combined reduction ($params->{amount} + $reduced) is higher than original amount ("
516 unless ( $original >= ( $params->{amount} + abs($reduced) ) );
518 my $status = { 'REFUND' => 'REFUNDED', 'DISCOUNT' => 'DISCOUNTED' };
521 $self->_result->result_source->schema->txn_do(
524 # A 'reduction' is a 'credit'
525 $reduction = Koha::Account::Line->new(
528 amount => 0 - $params->{amount},
529 credit_type_code => $params->{reduction_type},
531 amountoutstanding => 0 - $params->{amount},
532 manager_id => $params->{staff_id},
533 borrowernumber => $self->borrowernumber,
534 interface => $params->{interface},
535 branchcode => $params->{branch},
539 my $reduction_offset = Koha::Account::Offset->new(
541 credit_id => $reduction->accountlines_id,
542 type => uc( $params->{reduction_type} ),
543 amount => $params->{amount}
547 # Link reduction to charge (and apply as required)
548 my $debit_outstanding = $self->amountoutstanding;
549 if ( $debit_outstanding >= $params->{amount} ) {
554 offset_type => uc( $params->{reduction_type} )
557 $reduction->status('APPLIED')->store();
561 # Zero amount offset used to link original 'debit' to
563 my $link_reduction_offset = Koha::Account::Offset->new(
565 credit_id => $reduction->accountlines_id,
566 debit_id => $self->accountlines_id,
567 type => uc( $params->{reduction_type} ),
573 # Update status of original debit
574 $self->status( $status->{ $params->{reduction_type} } )->store;
578 $reduction->discard_changes;
584 my $debits = $account->outstanding_debits;
585 my $credit = $credit->apply( { debits => $debits, [ offset_type => $offset_type ] } );
587 Applies the credit to a given debits array reference.
589 =head4 arguments hashref
593 =item debits - Koha::Account::Lines object set of debits
595 =item offset_type (optional) - a string indicating the offset type (valid values are those from
596 the 'account_offset_types' table)
603 my ( $self, $params ) = @_;
605 my $debits = $params->{debits};
606 my $offset_type = $params->{offset_type} // 'Credit Applied';
608 unless ( $self->is_credit ) {
609 Koha::Exceptions::Account::IsNotCredit->throw(
610 error => 'Account line ' . $self->id . ' is not a credit'
614 my $available_credit = $self->amountoutstanding * -1;
616 unless ( $available_credit > 0 ) {
617 Koha::Exceptions::Account::NoAvailableCredit->throw(
618 error => 'Outstanding credit is ' . $available_credit . ' and cannot be applied'
622 my $schema = Koha::Database->new->schema;
624 $schema->txn_do( sub {
625 for my $debit ( @{$debits} ) {
627 unless ( $debit->is_debit ) {
628 Koha::Exceptions::Account::IsNotDebit->throw(
629 error => 'Account line ' . $debit->id . 'is not a debit'
632 my $amount_to_cancel;
633 my $owed = $debit->amountoutstanding;
635 if ( $available_credit >= $owed ) {
636 $amount_to_cancel = $owed;
638 else { # $available_credit < $debit->amountoutstanding
639 $amount_to_cancel = $available_credit;
642 # record the account offset
643 Koha::Account::Offset->new(
644 { credit_id => $self->id,
645 debit_id => $debit->id,
646 amount => $amount_to_cancel * -1,
647 type => $offset_type,
651 $available_credit -= $amount_to_cancel;
653 $self->amountoutstanding( $available_credit * -1 )->store;
654 $debit->amountoutstanding( $owed - $amount_to_cancel )->store;
656 # Attempt to renew the item associated with this debit if
658 if ( $self->credit_type_code ne 'FORGIVEN' && $debit->is_renewable ) {
659 my $outcome = $debit->renew_item( { interface => $params->{interface} } );
663 message => 'renewal',
668 $debit->discard_changes; # Refresh values from DB to clear floating point remainders
670 # Same logic exists in Koha::Account::pay
672 C4::Context->preference('MarkLostItemsAsReturned') =~
674 && $debit->debit_type_code
675 && $debit->debit_type_code eq 'LOST'
676 && $debit->amountoutstanding == 0
677 && $debit->itemnumber
679 $self->credit_type_code eq 'LOST_FOUND'
680 && $self->itemnumber == $debit->itemnumber
684 C4::Circulation::ReturnLostItem( $self->borrowernumber,
685 $debit->itemnumber );
688 last if $available_credit == 0;
697 $credit_accountline->payout(
699 payout_type => $payout_type,
700 register_id => $register_id,
701 staff_id => $staff_id,
702 interface => 'intranet',
707 Used to 'pay out' a credit to a user.
709 Payout type may be one of any existing payment types
711 Returns the payout debit line that is created via this transaction.
716 my ( $self, $params ) = @_;
718 # Make sure it is a credit we are paying out
719 unless ( $self->is_credit ) {
720 Koha::Exceptions::Account::IsNotCredit->throw(
721 error => 'Account line ' . $self->id . ' is not a credit' );
724 # Check for mandatory parameters
726 ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
727 for my $param (@mandatory) {
728 unless ( defined( $params->{$param} ) ) {
729 Koha::Exceptions::MissingParameter->throw(
730 error => "The $param parameter is mandatory" );
734 # Make sure there is outstanding credit to pay out
735 my $outstanding = -1 * $self->amountoutstanding;
737 $params->{amount} ? $params->{amount} : $outstanding;
738 Koha::Exceptions::Account::AmountNotPositive->throw(
739 error => 'Payout amount passed is not positive' )
740 unless ( $amount > 0 );
741 Koha::Exceptions::ParameterTooHigh->throw(
742 error => "Amount to payout ($amount) is higher than amountoutstanding ($outstanding)" )
743 unless ($outstanding >= $amount );
745 # Make sure we record the cash register for cash transactions
746 Koha::Exceptions::Account::RegisterRequired->throw()
747 if ( C4::Context->preference("UseCashRegisters")
748 && defined( $params->{payout_type} )
749 && ( $params->{payout_type} eq 'CASH' )
750 && !defined( $params->{cash_register} ) );
753 $self->_result->result_source->schema->txn_do(
756 # A 'payout' is a 'debit'
757 $payout = Koha::Account::Line->new(
761 debit_type_code => 'PAYOUT',
762 payment_type => $params->{payout_type},
763 amountoutstanding => $amount,
764 manager_id => $params->{staff_id},
765 borrowernumber => $self->borrowernumber,
766 interface => $params->{interface},
767 branchcode => $params->{branch},
768 register_id => $params->{cash_register}
772 my $payout_offset = Koha::Account::Offset->new(
774 debit_id => $payout->accountlines_id,
780 $self->apply( { debits => [$payout], offset_type => 'PAYOUT' } );
781 $self->status('PAID')->store;
785 $payout->discard_changes;
791 This method allows updating a debit or credit on a patron's account
793 $account_line->adjust(
796 type => $update_type,
797 interface => $interface
801 $update_type can be any of:
804 Authors Note: The intention here is that this method is only used
805 to adjust accountlines where the final amount is not yet known/fixed.
806 Incrementing fines are the only existing case at the time of writing,
807 all other forms of 'adjustment' should be recorded as distinct credits
808 or debits and applied, via an offset, to the corresponding debit or credit.
813 my ( $self, $params ) = @_;
815 my $amount = $params->{amount};
816 my $update_type = $params->{type};
817 my $interface = $params->{interface};
819 unless ( exists($Koha::Account::Line::allowed_update->{$update_type}) ) {
820 Koha::Exceptions::Account::UnrecognisedType->throw(
821 error => 'Update type not recognised'
825 my $debit_type_code = $self->debit_type_code;
826 my $account_status = $self->status;
830 $Koha::Account::Line::allowed_update->{$update_type}
833 && ( $Koha::Account::Line::allowed_update->{$update_type}
834 ->{$debit_type_code} eq $account_status )
838 Koha::Exceptions::Account::UnrecognisedType->throw(
839 error => 'Update type not allowed on this debit_type' );
842 my $schema = Koha::Database->new->schema;
847 my $amount_before = $self->amount;
848 my $amount_outstanding_before = $self->amountoutstanding;
849 my $difference = $amount - $amount_before;
850 my $new_outstanding = $amount_outstanding_before + $difference;
852 my $offset_type = $debit_type_code;
853 $offset_type .= ( $difference > 0 ) ? "_INCREASE" : "_DECREASE";
855 # Catch cases that require patron refunds
856 if ( $new_outstanding < 0 ) {
858 Koha::Patrons->find( $self->borrowernumber )->account;
859 my $credit = $account->add_credit(
861 amount => $new_outstanding * -1,
862 type => 'OVERPAYMENT',
863 interface => $interface,
864 ( $update_type eq 'overdue_update' ? ( item_id => $self->itemnumber ) : ()),
867 $new_outstanding = 0;
870 # Update the account line
875 amountoutstanding => $new_outstanding,
879 # Record the account offset
880 my $account_offset = Koha::Account::Offset->new(
882 debit_id => $self->id,
883 type => $offset_type,
884 amount => $difference
888 if ( C4::Context->preference("FinesLog") ) {
890 "FINES", 'UPDATE', #undef becomes UPDATE in UpdateFine
891 $self->borrowernumber,
893 { action => $update_type,
894 borrowernumber => $self->borrowernumber,
896 description => undef,
897 amountoutstanding => $new_outstanding,
898 debit_type_code => $self->debit_type_code,
900 itemnumber => $self->itemnumber,
904 ) if ( $update_type eq 'overdue_update' );
914 my $bool = $line->is_credit;
921 return defined $self->credit_type_code;
926 my $bool = $line->is_debit;
933 return !$self->is_credit;
936 =head3 to_api_mapping
938 This method returns the mapping for representing a Koha::Account::Line object
945 accountlines_id => 'account_line_id',
946 credit_number => undef,
947 credit_type_code => 'credit_type',
948 debit_type_code => 'debit_type',
949 amountoutstanding => 'amount_outstanding',
950 borrowernumber => 'patron_id',
951 branchcode => 'library_id',
952 issue_id => 'checkout_id',
953 itemnumber => 'item_id',
954 manager_id => 'user_id',
955 note => 'internal_note',
956 register_id => 'cash_register_id',
963 my $bool = $line->is_renewable;
971 $self->amountoutstanding == 0 &&
972 $self->debit_type_code &&
973 $self->debit_type_code eq 'OVERDUE' &&
975 $self->status eq 'UNRETURNED' &&
983 my $renew_result = $line->renew_item;
985 Conditionally attempt to renew an item and return the outcome. This is
986 as a consequence of the fine on an item being fully paid off.
987 Caller must call is_renewable before.
992 my ($self, $params) = @_;
996 # We want to reject the call to renew if:
997 # - The RenewAccruingItemWhenPaid syspref is off
999 # - The RenewAccruingItemInOpac syspref is off
1000 # - There is an interface param passed and it's value is 'opac'
1003 !C4::Context->preference('RenewAccruingItemWhenPaid') ||
1005 !C4::Context->preference('RenewAccruingItemInOpac') &&
1006 $params->{interface} &&
1007 $params->{interface} eq 'opac'
1013 my $itemnumber = $self->item->itemnumber;
1014 my $borrowernumber = $self->patron->borrowernumber;
1015 my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1020 my $due_date = C4::Circulation::AddRenewal(
1023 $self->{branchcode},
1029 itemnumber => $itemnumber,
1030 due_date => $due_date,
1035 itemnumber => $itemnumber,
1045 Specific store method to generate credit number before saving
1052 my $AutoCreditNumber = C4::Context->preference('AutoCreditNumber');
1053 my $credit_number_enabled = $self->is_credit && $self->credit_type->credit_number_enabled;
1055 if ($AutoCreditNumber && $credit_number_enabled && !$self->in_storage) {
1056 if (defined $self->credit_number) {
1057 Koha::Exceptions::Account->throw('AutoCreditNumber is enabled but credit_number is already defined');
1060 my $rs = Koha::Database->new->schema->resultset($self->_type);
1062 if ($AutoCreditNumber eq 'incremental') {
1063 my $max = $rs->search({
1064 credit_number => { -regexp => '^[0-9]+$' }
1066 select => \'CAST(credit_number AS UNSIGNED)',
1067 as => ['credit_number'],
1068 })->get_column('credit_number')->max;
1070 $self->credit_number($max + 1);
1071 } elsif ($AutoCreditNumber eq 'annual') {
1072 my $now = dt_from_string;
1073 my $prefix = sprintf('%d-', $now->year);
1074 my $max = $rs->search({
1076 credit_number => { -regexp => '[0-9]{4}$' },
1077 credit_number => { -like => "$prefix%" },
1079 })->get_column('credit_number')->max;
1080 $max //= $prefix . '0000';
1081 my $incr = substr($max, length $prefix);
1082 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1083 } elsif ($AutoCreditNumber eq 'branchyyyymmincr') {
1084 my $userenv = C4::Context->userenv;
1086 my $branch = $userenv->{branch};
1087 my $now = dt_from_string;
1088 my $prefix = sprintf('%s%d%02d', $branch, $now->year, $now->month);
1089 my $pattern = $prefix;
1090 $pattern =~ s/([\?%_])/\\$1/g;
1091 my $max = $rs->search({
1093 credit_number => { -regexp => '[0-9]{4}$' },
1094 credit_number => { -like => "$pattern%" },
1096 })->get_column('credit_number')->max;
1097 $max //= $prefix . '0000';
1098 my $incr = substr($max, length $prefix);
1099 $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1));
1104 return $self->SUPER::store();
1107 =head2 Internal methods
1116 return 'Accountline';
1121 =head2 Name mappings
1123 =head3 $allowed_update
1127 our $allowed_update = { 'overdue_update' => { 'OVERDUE' => 'UNRETURNED' } };
1131 Kyle M Hall <kyle@bywatersolutions.com >
1132 Tomás Cohen Arazi <tomascohen@theke.io>
1133 Martin Renvoize <martin.renvoize@ptfs-europe.com>