Bugzilla – Attachment 187902 Details for
Bug 30328
Add ability to generate barcode with library specific prefix
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 30328: Add ability to generate barcode with branch specific prefix
0001-Bug-30328-Add-ability-to-generate-barcode-with-branc.patch (text/plain), 19.01 KB, created by
Emmi Takkinen
on 2025-10-15 11:33:46 UTC
(
hide
)
Description:
Bug 30328: Add ability to generate barcode with branch specific prefix
Filename:
MIME Type:
Creator:
Emmi Takkinen
Created:
2025-10-15 11:33:46 UTC
Size:
19.01 KB
patch
obsolete
>From 962d7f6abfd784035c1eb939cdc946c15fb6e6c6 Mon Sep 17 00:00:00 2001 >From: Emmi Takkinen <emmi.takkinen@koha-suomi.fi> >Date: Tue, 22 Mar 2022 13:17:19 +0200 >Subject: [PATCH] Bug 30328: Add ability to generate barcode with branch > specific prefix > >We should add more flexibility to generating barcodes by letting libraries >define branch specific prefix for their barcodes. This patch adds new option >"preyymmddts" in systempreference "autoBarcode" and new systempreference >"BarcodePrefix" to define branch specific prefix. > >Test plan: > >1. Apply patch and update database >2. Set syspref "autoBarcode" as "preyymmddts" >3. Add some values to syspref "Barcodeprefix" e.g.: > Default: DEF > CPL: CPL > FFL: FFL >4. Now change your library to CPL (if needed) and add an item >5. Click barcode input field > => barcode should be CPL<current_year><current_month><current_day><timestamp> >6. Add another item and click barcode field > => barcode should be CPL<current_year><current_month><current_day><timestamp> >7. Change your library to FFL and add an item > => barcode should now be FFL<current_year><current_month><current_day><timestamp> >8. Change your library to e.g. FPL (or another as long as it doesn't have prefix value >in "Barcodeprefix"), add an item and click barcode field > => barcode should now be DEF<current_year><current_month><current_day><timestamp> >9. Try to add multiple items > => barcodes timestamp value should change based on time barcode was generated. > >Also prove t/db_dependent/Barcodes_ValueBuilder.t and t/Barcodes_preyymmddts.t > >Sponsored-by: Koha-Suomi Oy >--- > C4/Barcodes.pm | 2 + > C4/Barcodes/ValueBuilder.pm | 54 +++++++++ > C4/Barcodes/preyymmddts.pm | 114 ++++++++++++++++++ > cataloguing/additem.pl | 10 +- > cataloguing/value_builder/barcode.pl | 4 + > cataloguing/value_builder/barcode_manual.pl | 4 + > .../data/mysql/atomicupdate/bug_30328.pl | 21 ++++ > installer/data/mysql/mandatory/sysprefs.sql | 3 +- > .../admin/preferences/cataloguing.pref | 9 +- > t/Barcodes_preyymmddts.t | 11 ++ > t/db_dependent/Barcodes_ValueBuilder.t | 32 ++++- > 11 files changed, 259 insertions(+), 5 deletions(-) > create mode 100644 C4/Barcodes/preyymmddts.pm > create mode 100755 installer/data/mysql/atomicupdate/bug_30328.pl > create mode 100755 t/Barcodes_preyymmddts.t > >diff --git a/C4/Barcodes.pm b/C4/Barcodes.pm >index fa739ec6ba..269819978d 100644 >--- a/C4/Barcodes.pm >+++ b/C4/Barcodes.pm >@@ -27,6 +27,7 @@ use C4::Barcodes::hbyymmincr; > use C4::Barcodes::annual; > use C4::Barcodes::incremental; > use C4::Barcodes::EAN13; >+use C4::Barcodes::preyymmddts; > > use vars qw($max $prefformat); > >@@ -174,6 +175,7 @@ our $types = { > hbyymmincr => sub { C4::Barcodes::hbyymmincr->new_object(@_); }, > OFF => sub { C4::Barcodes::OFF->new_object(@_); }, > EAN13 => sub { C4::Barcodes::EAN13->new_object(@_); }, >+ preyymmddts => sub { C4::Barcodes::preyymmddts->new_object(@_); }, > }; > > sub new { >diff --git a/C4/Barcodes/ValueBuilder.pm b/C4/Barcodes/ValueBuilder.pm >index b12fd5bacf..c809f71498 100644 >--- a/C4/Barcodes/ValueBuilder.pm >+++ b/C4/Barcodes/ValueBuilder.pm >@@ -92,6 +92,60 @@ sub get_barcode { > return $nextnum; > } > >+package C4::Barcodes::ValueBuilder::preyymmddts; >+use C4::Context; >+use YAML::XS; >+use Time::HiRes qw(time); >+use POSIX qw(strftime); >+my $DEBUG = 0; >+ >+sub get_barcode { >+ my ($args) = @_; >+ my $nextnum; >+ my $barcode; >+ my $branchcode = $args->{branchcode}; >+ my $query; >+ my $sth; >+ >+ # Getting the barcodePrefixes >+ my $branchPrefixes = C4::Context->preference("BarcodePrefix"); >+ my $yaml = YAML::XS::Load( >+ Encode::encode( >+ 'UTF-8', >+ $branchPrefixes, >+ Encode::FB_CROAK >+ ) >+ ); >+ >+ my $prefix = $yaml->{$branchcode} || $yaml->{'Default'}; >+ my $date = strftime "%H%M%S", localtime; >+ my $year = substr( $args->{year}, -2 ); >+ $query = "SELECT MAX(CAST(SUBSTRING(barcode,-1) AS signed)) from items where barcode REGEXP ?"; >+ $sth = C4::Context->dbh->prepare($query); >+ $sth->execute("^$prefix$year$args->{mon}$args->{day}$date"); >+ >+ while ( my ($count) = $sth->fetchrow_array ) { >+ $nextnum = $count if $count; >+ $nextnum = 0 if $nextnum && $nextnum == 9; >+ } >+ >+ $nextnum++; >+ $barcode = $prefix . $year . $args->{mon} . $args->{day} . $date . $nextnum; >+ >+ my $scr = qq~ >+ let elt = \$("#"+id); >+ let branchcode = elt.parents('fieldset.rows:first') >+ .find('input[name="kohafield"][value="items.homebranch"]') >+ .siblings("select") >+ .val(); >+ if ( \$(elt).val() == '' ) { >+ \$(elt).val('$barcode'); >+ } >+ ~; >+ >+ return $barcode, $scr; >+} >+ > 1; > > =head1 Barcodes::ValueBuilder >diff --git a/C4/Barcodes/preyymmddts.pm b/C4/Barcodes/preyymmddts.pm >new file mode 100644 >index 0000000000..f8644aefb2 >--- /dev/null >+++ b/C4/Barcodes/preyymmddts.pm >@@ -0,0 +1,114 @@ >+package C4::Barcodes::preyymmddts; >+ >+# Copyright 2022 Koha Development team >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use strict; >+use warnings; >+ >+use Carp qw( carp ); >+ >+use C4::Context; >+ >+use Koha::DateUtils qw( dt_from_string output_pref ); >+use POSIX qw( strftime ); >+ >+use vars qw(@ISA); >+ >+BEGIN { >+ @ISA = qw(C4::Barcodes); >+} >+ >+sub new_object { >+ my $class = shift; >+ my $type = ref($class) || $class; >+ my $self = $type->default_self('preyymmddts'); >+ >+ my $branchcode = C4::Context->userenv->{'branch'}; >+ my $branchPrefixes = C4::Context->preference("BarcodePrefix"); >+ my $yaml = YAML::XS::Load( >+ Encode::encode( >+ 'UTF-8', >+ $branchPrefixes, >+ Encode::FB_CROAK >+ ) >+ ); >+ my $prefix = $yaml->{$branchcode} || $yaml->{'Default'}; >+ >+ $self->{prefix} = $prefix; >+ $self->{datetime} = output_pref( { dt => dt_from_string, dateformat => 'iso', dateonly => 1 } ); >+ >+ return bless $self, $type; >+} >+ >+sub initial { >+ my $self = shift; >+ >+ return get_head($self) . '1'; >+} >+ >+sub db_max { >+ my $self = shift; >+ >+ my $barcode = get_head($self); >+ >+ my $query = "SELECT MAX(CAST(SUBSTRING(barcode,-1) AS signed)) from items where barcode REGEXP ?"; >+ my $sth = C4::Context->dbh->prepare($query); >+ $sth->execute("^$barcode"); >+ >+ my $nextnum; >+ while ( my ($count) = $sth->fetchrow_array ) { >+ $nextnum = $count if $count; >+ $nextnum = 0 if $nextnum && $nextnum == 9; >+ } >+ >+ return $nextnum; >+} >+ >+sub parse { >+ my $self = shift; >+ >+ my $head = get_head($self); >+ my $incr = (@_) ? shift : $self->value; >+ my $barcode = $head . $incr; >+ unless ($incr) { >+ carp "Barcode '$barcode' has no incrementing part!"; >+ return ( $barcode, undef, undef ); >+ } >+ >+ return ( $head, $incr, '' ); >+} >+ >+sub get_head { >+ my $self = shift; >+ >+ my $prefix = $self->{prefix}; >+ my ( $year, $month, $day ) = split( '-', $self->{datetime} ); >+ $year = substr( $year, -2 ); >+ my $date = strftime "%H%M%S", localtime; >+ >+ my $barcode = $prefix . $year . $month . $day . $date; >+ >+ return $barcode; >+} >+ >+BEGIN { >+ @ISA = qw(C4::Barcodes); >+} >+ >+1; >+__END__ >diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl >index 5c3e200512..521adc3bb1 100755 >--- a/cataloguing/additem.pl >+++ b/cataloguing/additem.pl >@@ -426,8 +426,14 @@ if ( $op eq "cud-additem" ) { > if ($barcodevalue) { > > # Getting a new barcode (if it is not the first iteration or the barcode we tried already exists) >- $barcodevalue = $barcodeobj->next_value($oldbarcode) >- if ( $i > 0 || $exist_itemnumber ); >+ if ( C4::Context->preference("autoBarcode") eq 'preyymmddts' ) { >+ my $barcodeobj2 = C4::Barcodes->new('preyymmddts'); >+ $barcodevalue = $barcodeobj2->value() >+ if ( $i > 0 || $exist_itemnumber ); >+ } else { >+ $barcodevalue = $barcodeobj->next_value($oldbarcode) >+ if ( $i > 0 || $exist_itemnumber ); >+ } > > # Putting it into the record > if ($barcodevalue) { >diff --git a/cataloguing/value_builder/barcode.pl b/cataloguing/value_builder/barcode.pl >index 6ed165e260..8ef7dfd4cb 100755 >--- a/cataloguing/value_builder/barcode.pl >+++ b/cataloguing/value_builder/barcode.pl >@@ -47,6 +47,7 @@ my $builder = sub { > # find today's date > ( $args{year}, $args{mon}, $args{day} ) = split( '-', dt_from_string()->ymd() ); > ( $args{tag}, $args{subfield} ) = GetMarcFromKohaField("items.barcode"); >+ ( $args{branchcode} ) = C4::Context->userenv->{'branch'}; > > my $nextnum; > my $scr; >@@ -82,6 +83,9 @@ my $builder = sub { > warn "ERROR: invalid EAN-13 $nextnum, using increment"; > $nextnum++; > } >+ } elsif ( $autoBarcodeType eq 'preyymmddts' ) >+ { # Generates a barcode where pre = branch specific prefix set on systempreference BarcodePrefix, yymmdd = year/month/day catalogued, ts = timestamp catalogued >+ ( $nextnum, $scr ) = C4::Barcodes::ValueBuilder::preyymmddts::get_barcode( \%args ); > } else { > warn "ERROR: unknown autoBarcode: $autoBarcodeType"; > } >diff --git a/cataloguing/value_builder/barcode_manual.pl b/cataloguing/value_builder/barcode_manual.pl >index 88c7a89a2e..ae732d6d26 100755 >--- a/cataloguing/value_builder/barcode_manual.pl >+++ b/cataloguing/value_builder/barcode_manual.pl >@@ -48,6 +48,7 @@ my $builder = sub { > # find today's date > ( $args{year}, $args{mon}, $args{day} ) = split( '-', dt_from_string()->ymd() ); > ( $args{tag}, $args{subfield} ) = GetMarcFromKohaField("items.barcode"); >+ ( $args{branchcode} ) = C4::Context->userenv->{'branch'}; > > my $nextnum; > my $scr; >@@ -64,6 +65,9 @@ my $builder = sub { > } elsif ( $autoBarcodeType eq 'hbyymmincr' ) > { # Generates a barcode where hb = home branch Code, yymm = year/month catalogued, incr = incremental number, reset yearly -fbcit > ( $nextnum, $scr ) = C4::Barcodes::ValueBuilder::hbyymmincr::get_barcode( \%args ); >+ } elsif ( $autoBarcodeType eq 'preyymmddts' ) >+ { # Generates a barcode where pre = branch specific prefix set on systempreference BarcodePrefix, yymmdd = year/month/day catalogued, ts = timestamp catalogued >+ ( $nextnum, $scr ) = C4::Barcodes::ValueBuilder::preyymmddts::get_barcode( \%args ); > } > > # default js body (if not filled by hbyymmincr) >diff --git a/installer/data/mysql/atomicupdate/bug_30328.pl b/installer/data/mysql/atomicupdate/bug_30328.pl >new file mode 100755 >index 0000000000..ded55d9ed6 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/bug_30328.pl >@@ -0,0 +1,21 @@ >+use Modern::Perl; >+ >+return { >+ bug_number => "30328", >+ description => "Add option to create barcode with branch specific prefix", >+ up => sub { >+ my ($args) = @_; >+ my ( $dbh, $out ) = @$args{qw(dbh out)}; >+ >+ # Do you stuffs here >+ $dbh->do( >+ q{ UPDATE IGNORE systempreferences SET options = 'incremental|annual|hbyymmincr|EAN13|preyymmddts|OFF' , explanation = '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; preyymmddts of the form PRE2021030001 where PRE = branch specific prefix set on systempreference BarcodePrefix' WHERE variable = 'autoBarcode'} >+ ); >+ $dbh->do( >+ q{ INSERT IGNORE INTO systempreferences ( variable, value, options, explanation, type ) VALUES ('BarcodePrefix','','','Defines the barcode prefixes when the autoBarcode value is set as preyymmddts','Free')} >+ ); >+ >+ # Print useful stuff here >+ say $out "Update is going well so far"; >+ }, >+}; >diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql >index 0d77d5ba94..6cb49b7dbe 100644 >--- a/installer/data/mysql/mandatory/sysprefs.sql >+++ b/installer/data/mysql/mandatory/sysprefs.sql >@@ -87,7 +87,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('AuthorLinkSortOrder','asc','asc|dsc|az|za','Specify the default sort order for author links','Choice'), > ('AuthSuccessLog','0',NULL,'If enabled, log successful authentications','YesNo'), > ('AutoApprovePatronProfileSettings', '0', '', 'Automatically approve patron profile changes from the OPAC.', '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'), >+('autoBarcode','OFF','incremental|annual|hbyymmincr|EAN13|preyymmddts|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; preyymmddts of the form PRE2021030001 where PRE = branch specific prefix set on systempreference BarcodePrefix','Choice'), > ('AutoClaimReturnStatusOnCheckin','','NULL','When in use this system preference will automatically resolve the claim return and will update the lost authorized value upon check in.','Free'), > ('AutoClaimReturnStatusOnCheckout','','NULL','When in use this system preference will automatically resolve the claim return and will update the lost authorized value upon check out.','Free'), > ('autoControlNumber','OFF','biblionumber|OFF','Used to autogenerate a Control Number: biblionumber will be as biblionumber, OFF will leave the field as it is;','Choice'), >@@ -117,6 +117,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('BakerTaylorEnabled','0','','Enable or disable all Baker & Taylor features.','YesNo'), > ('BakerTaylorPassword','','','Baker & Taylor Password for Content Cafe (external content)','Free'), > ('BakerTaylorUsername','','','Baker & Taylor Username for Content Cafe (external content)','Free'), >+('BarcodePrefix','','','Defines the barcode prefixes when the autoBarcode value is set as preyymmddts','Free'), > ('BarcodeSeparators','\\s\\r\\n','','Splitting characters for barcodes','Free'), > ('BasketConfirmations','1','always ask for confirmation.|do not ask for confirmation.','When closing or reopening a basket,','Choice'), > ('BatchCheckouts','0','','Enable or disable batch checkouts','YesNo'), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref >index 9c62cae068..304157309f 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref >@@ -143,6 +143,7 @@ Cataloging: > annual: generated in the form <year>-0001, <year>-0002. > hbyymmincr: generated in the form <branchcode>yymm0001. > EAN13: incremental EAN-13 barcodes. >+ preyymmddts: generated in the form <prefix>yymmdd<timestamp>. > "OFF": not generated automatically. > - > - When a new item is added, >@@ -217,6 +218,12 @@ Cataloging: > 1: Strip > 0: "Don't strip" > - leading and trailing whitespace characters (including spaces, tabs, line breaks and carriage returns) and inner newlines from data fields when cataloguing bibliographic and authority records. The leader and control fields will not be affected. >+ - >+ - "Define branch specific barcode prefix:" >+ - "This is a YAML config." >+ - pref: BarcodePrefix >+ type: textarea >+ class: code > Display: > - > - 'Separate main entry and subdivisions with ' >@@ -408,4 +415,4 @@ Cataloging: > - "<br/>" > - "All values of repeating tags and subfields will be printed with the given RIS tag." > - "<br/>" >- - "Use of TY ( record type ) as a key will <em>replace</em> the default TY with the field value of your choosing." >\ No newline at end of file >+ - "Use of TY ( record type ) as a key will <em>replace</em> the default TY with the field value of your choosing." >diff --git a/t/Barcodes_preyymmddts.t b/t/Barcodes_preyymmddts.t >new file mode 100755 >index 0000000000..ef3d7eb9d1 >--- /dev/null >+++ b/t/Barcodes_preyymmddts.t >@@ -0,0 +1,11 @@ >+#!/usr/bin/perl >+ >+use strict; >+use warnings; >+ >+use Test::NoWarnings; >+use Test::More tests => 2; >+ >+BEGIN { >+ use_ok('C4::Barcodes::preyymmddts'); >+} >diff --git a/t/db_dependent/Barcodes_ValueBuilder.t b/t/db_dependent/Barcodes_ValueBuilder.t >index 15328e8572..8626e85b22 100755 >--- a/t/db_dependent/Barcodes_ValueBuilder.t >+++ b/t/db_dependent/Barcodes_ValueBuilder.t >@@ -17,12 +17,14 @@ > use Modern::Perl; > > use Test::NoWarnings; >-use Test::More tests => 10; >+use Test::More tests => 13; > use Test::MockModule; > use t::lib::TestBuilder; > > use Koha::Database; > >+use t::lib::Mocks; >+ > BEGIN { > use_ok( 'C4::Barcodes::ValueBuilder', qw( get_barcode ) ); > } >@@ -66,4 +68,32 @@ my $item_5 = $builder->build_sample_item( { barcode => '978e0143019375' } ); > is( $nextnum, '979', 'incremental barcode' ); > is( $scr, undef, 'incremental javascript' ); > >+$dbh->do(q|DELETE FROM items|); >+my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } ); >+ >+my $prefix_yaml = 'Default: DEF >+' . $library_1->branchcode . ': TEST'; >+t::lib::Mocks::mock_preference( 'BarcodePrefix', $prefix_yaml ); >+ >+my $item_6 = $builder->build_sample_item( >+ { >+ barcode => 'TEST1207301414381', >+ homebranch => $library_1->branchcode >+ } >+); >+ >+( $args{branchcode} ) = $library_1->branchcode; >+( $nextnum, $scr ) = C4::Barcodes::ValueBuilder::preyymmddts::get_barcode( \%args ); >+ >+# test if begining of new barcode matches prefix and date args >+like( $nextnum, qr/TEST120730/, 'preyymmddts barcode test branch specific prefix' ); >+ok( length($scr) > 0, 'preyymmddtsr javascript' ); >+ >+$dbh->do(q|DELETE FROM items|); >+my $library_2 = $builder->build_object( { class => 'Koha::Libraries' } ); >+ >+( $args{branchcode} ) = $library_2->branchcode; >+( $nextnum, $scr ) = C4::Barcodes::ValueBuilder::preyymmddts::get_barcode( \%args ); >+like( $nextnum, qr/DEF120730/, 'preyymmddts barcode test default prefix' ); >+ > $schema->storage->txn_rollback; >-- >2.34.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 30328
:
132221
|
132954
|
134009
|
134202
|
134206
|
139350
|
187145
|
187146
| 187902