@@ -, +, @@ credits - Do not automatically generate credit numbers. This is the current behaviour and the default syspref value. - Automatically generate credit numbers in the form -0001 (annual) - Automatically generate credit numbers in the form yyyymm0001 (branchyyyymmincr) where is the branch where the user (staff member) is logged in - Automatically generate credit numbers in the form 1, 2, 3 (incremental) column credit_number in table account-fines. It will be easier for testing that this credit has no number generated 1, 2, 3, ... '2020-0001', '2020-0002', ... 'BRANCHA2020020001', 'BRANCHA2020020002', ... (assuming you are connected to library BRANCHA, and it's February 2020) 'BRANCHB2020020001', 'BRANCHB2020020002', ... somewhere. Go back to Transactions tab and click on 'Print' for one line that has a credit number. Make sure the number is there. --- Koha/Account/Line.pm | 58 ++++++++++++++++++++++ admin/columns_settings.yml | 3 ++ installer/data/mysql/atomicupdate/bug-19036.perl | 11 ++++ installer/data/mysql/kohastructure.sql | 1 + installer/data/mysql/sysprefs.sql | 1 + .../en/modules/admin/preferences/accounting.pref | 7 +++ .../prog/en/modules/members/boraccount.tt | 2 + t/db_dependent/Koha/Account.t | 48 ++++++++++++++++++ 8 files changed, 131 insertions(+) create mode 100644 installer/data/mysql/atomicupdate/bug-19036.perl --- a/Koha/Account/Line.pm +++ a/Koha/Account/Line.pm @@ -876,6 +876,64 @@ sub renew_item { } +=head3 store + +Specific store method to generate credit number before saving + +=cut + +sub store { + my ($self) = @_; + + my $AutoCreditNumber = C4::Context->preference('AutoCreditNumber'); + if ($AutoCreditNumber && !$self->in_storage && $self->is_credit && !$self->credit_number) { + my $rs = Koha::Database->new->schema->resultset($self->_type); + + if ($AutoCreditNumber eq 'incremental') { + my $max = $rs->search({ + credit_number => { -regexp => '^[0-9]+$' } + }, { + select => \'CAST(credit_number AS UNSIGNED)', + as => ['credit_number'], + })->get_column('credit_number')->max; + $max //= 0; + $self->credit_number($max + 1); + } elsif ($AutoCreditNumber eq 'annual') { + my $now = DateTime->now; + my $prefix = sprintf('%d-', $now->year); + my $max = $rs->search({ + -and => [ + credit_number => { -regexp => '[0-9]{4}$' }, + credit_number => { -like => "$prefix%" }, + ], + })->get_column('credit_number')->max; + $max //= $prefix . '0000'; + my $incr = substr($max, length $prefix); + $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1)); + } elsif ($AutoCreditNumber eq 'branchyyyymmincr') { + my $userenv = C4::Context->userenv; + if ($userenv) { + my $branch = $userenv->{branch}; + my $now = DateTime->now; + my $prefix = sprintf('%s%d%02d', $branch, $now->year, $now->month); + my $pattern = $prefix; + $pattern =~ s/([\?%_])/\\$1/g; + my $max = $rs->search({ + -and => [ + credit_number => { -regexp => '[0-9]{4}$' }, + credit_number => { -like => "$pattern%" }, + ], + })->get_column('credit_number')->max; + $max //= $prefix . '0000'; + my $incr = substr($max, length $prefix); + $self->credit_number(sprintf('%s%04d', $prefix, $incr + 1)); + } + } + } + + return $self->SUPER::store(); +} + =head2 Internal methods =cut --- a/admin/columns_settings.yml +++ a/admin/columns_settings.yml @@ -651,6 +651,9 @@ modules: - columnname: date - + columnname: credit_number + is_hidden: 1 + - columnname: account_type - columnname: description --- a/installer/data/mysql/atomicupdate/bug-19036.perl +++ a/installer/data/mysql/atomicupdate/bug-19036.perl @@ -0,0 +1,11 @@ +$DBversion = 'XXX'; +if (CheckVersion($DBversion)) { + unless (column_exists('accountlines', 'credit_number')) { + $dbh->do('ALTER TABLE accountlines ADD COLUMN credit_number VARCHAR(20) NULL DEFAULT NULL COMMENT "autogenerated number for credits" AFTER debit_type_code'); + } + + $dbh->do('INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) VALUES(?, ?, ?, ?, ?)', undef, 'AutoCreditNumber', '', '', 'Automatically generate a number for account credits', 'Choice'); + + SetVersion($DBversion); + print "Upgrade to $DBversion done (Bug 19036 - Add column accountlines.credit_number)\n"; +} --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -2723,6 +2723,7 @@ CREATE TABLE `accountlines` ( `description` LONGTEXT, `credit_type_code` varchar(80) default NULL, `debit_type_code` varchar(80) default NULL, + `credit_number` varchar(20) NULL DEFAULT NULL COMMENT 'autogenerated number for credits', `status` varchar(16) default NULL, `payment_type` varchar(80) default NULL, -- optional authorised value PAYMENT_TYPE `amountoutstanding` decimal(28,6) default NULL, --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -70,6 +70,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('AuthSuccessLog','',NULL,'If enabled, log successful authentications','YesNo'), ('autoBarcode','OFF','incremental|annual|hbyymmincr|EAN13|OFF','Used to autogenerate a barcode: incremental will be of the form 1, 2, 3; annual of the form 2007-0001, 2007-0002; hbyymmincr of the form HB08010001 where HB=Home Branch','Choice'), ('AutoCreateAuthorities','0',NULL,'Automatically create authorities that do not exist when cataloging records.','YesNo'), +('AutoCreditNumber', '', '', 'Automatically generate a number for account credits', 'Choice'), ('AutoEmailOpacUser','0',NULL,'Sends notification emails containing new account details to patrons - when account is created.','YesNo'), ('AutoEmailPrimaryAddress','OFF','email|emailpro|B_email|cardnumber|OFF','Defines the default email address where \'Account Details\' emails are sent.','Choice'), ('AutoShareWithMana','subscription','','defines datas automatically shared with mana','multiple'), --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/accounting.pref @@ -33,3 +33,10 @@ Accounting: yes: "Enable" no: "Disable" - " the point of sale feature to allow anonymous transactions with the accounting system. (Requires UseCashRegisters)" + - + - pref: AutoCreditNumber + choices: + '': 'Do not automatically generate credit numbers' + annual: 'Automatically generate credit numbers in the form -0001' + branchyyyymmincr: 'Automatically generate credit numbers in the form yyyymm0001' + incremental: 'Automatically generate credit numbers in the form 1, 2, 3' --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt @@ -45,6 +45,7 @@ Date + Credit number Account type Description of charges Barcode @@ -64,6 +65,7 @@ [% account.date |$KohaDates %] + [% account.credit_number | html %] [% PROCESS account_type_description account=account %] [%- IF account.payment_type %][% AuthorisedValues.GetByCode('PAYMENT_TYPE', account.payment_type) | html %][% END %] --- a/t/db_dependent/Koha/Account.t +++ a/t/db_dependent/Koha/Account.t @@ -1049,3 +1049,51 @@ subtest 'Koha::Account::Line::apply() handles lost items' => sub { $schema->storage->txn_rollback; }; + +subtest 'Koha::Account::pay() generates credit number' => sub { + plan tests => 34; + + $schema->storage->txn_begin; + + Koha::Account::Lines->delete(); + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + my $library = $builder->build_object( { class => 'Koha::Libraries' } ); + my $account = $patron->account; + + my $context = Test::MockModule->new('C4::Context'); + $context->mock( 'userenv', { branch => $library->id } ); + + my $now = DateTime->now; + my $year = $now->year; + my $month = $now->month; + my ($accountlines_id, $accountline); + + t::lib::Mocks::mock_preference('AutoCreditNumber', ''); + $accountlines_id = $account->pay({ amount => '1.00', library_id => $library->id })->{payment_id}; + $accountline = Koha::Account::Lines->find($accountlines_id); + is($accountline->credit_number, undef, 'No credit number is generated when syspref is off'); + + t::lib::Mocks::mock_preference('AutoCreditNumber', 'incremental'); + for my $i (1..11) { + $accountlines_id = $account->pay({ amount => '1.00', library_id => $library->id })->{payment_id}; + $accountline = Koha::Account::Lines->find($accountlines_id); + is($accountline->credit_number, $i); + } + + t::lib::Mocks::mock_preference('AutoCreditNumber', 'annual'); + for my $i (1..11) { + $accountlines_id = $account->pay({ amount => '1.00', library_id => $library->id })->{payment_id}; + $accountline = Koha::Account::Lines->find($accountlines_id); + is($accountline->credit_number, sprintf('%s-%04d', $year, $i)); + } + + t::lib::Mocks::mock_preference('AutoCreditNumber', 'branchyyyymmincr'); + for my $i (1..11) { + $accountlines_id = $account->pay({ amount => '1.00', library_id => $library->id })->{payment_id}; + $accountline = Koha::Account::Lines->find($accountlines_id); + is($accountline->credit_number, sprintf('%s%d%02d%04d', $library->id, $year, $month, $i)); + } + + $schema->storage->txn_rollback; +}; --