From 224c6decd6e0a7b1f124dcdbb2674ab015966199 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Wed, 2 Sep 2020 09:17:31 -0400 Subject: [PATCH] Bug 26351: Add plugin hooks to transform item barcodes Some of our partners have unusual barcode requirements that have required us to transform scanned barcodes using javascript. This is not the most reliable method. It would make more sense to have Koha transform the barcodes on the backend using a plugin. We should add hooks to transform and generate new item and patron barcodes. Test Plan: 1) Apply this patch 2) Download and install the Barcode Transformer plugin https://github.com/bywatersolutions/koha-plugin-barcode-transformer/releases/ 3) Go to the plugin configuration page, set the configuration to the example configuration from the same page 4) In the item barcode field on the checkin and checkout pages, and anywhere else you can scan an item barcode, type in some valid barcodes, but prefix them with X and postfix them with Y, e.g. X123456Y 5) Note the letters are removed by Koha! Signed-off-by: Lucas Gass Signed-off-by: Martin Renvoize --- C4/Circulation.pm | 73 ++++++++++++++------------- C4/ILSDI/Services.pm | 2 + C4/Items.pm | 1 + Koha/Item.pm | 3 ++ cataloguing/additem.pl | 4 ++ circ/circulation.pl | 2 + circ/returns.pl | 3 ++ offline_circ/process_koc.pl | 9 ++++ opac/sco/sco-main.pl | 3 ++ t/db_dependent/Koha/Plugins/Plugins.t | 4 +- t/lib/Koha/Plugin/Test.pm | 9 ++++ tools/batchMod.pl | 4 ++ tools/inventory.pl | 5 ++ 13 files changed, 86 insertions(+), 36 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 50c436ecba..033d00e83c 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -19,59 +19,61 @@ package C4::Circulation; # along with Koha; if not, see . use Modern::Perl; + +use Algorithm::CheckDigits; +use Carp; +use Data::Dumper; +use Date::Calc qw( + Today + Today_and_Now + Add_Delta_YM + Add_Delta_DHMS + Date_to_Days + Day_of_Week + Add_Delta_Days +); use DateTime; +use List::MoreUtils qw( uniq any ); use POSIX qw( floor ); -use Koha::DateUtils; -use C4::Context; -use C4::Stats; -use C4::Reserves; +use Scalar::Util qw( looks_like_number ); +use Try::Tiny; + +use C4::Accounts; use C4::Biblio; +use C4::Context; +use C4::Debug; +use C4::ItemCirculationAlertPreference; use C4::Items; +use C4::Log; # logaction use C4::Members; -use C4::Accounts; -use C4::ItemCirculationAlertPreference; use C4::Message; -use C4::Debug; -use C4::Log; # logaction use C4::Overdues qw(CalcFine UpdateFine get_chargeable_units); +use C4::Reserves; use C4::RotatingCollections qw(GetCollectionItemBranches); -use Algorithm::CheckDigits; +use C4::Stats; -use Data::Dumper; +use Koha::Account::Lines; +use Koha::Account::Offsets; use Koha::Account; use Koha::AuthorisedValues; use Koha::Biblioitems; -use Koha::DateUtils; use Koha::Calendar; +use Koha::Charges::Fees; +use Koha::Checkouts::ReturnClaims; use Koha::Checkouts; +use Koha::Config::SysPrefs; +use Koha::Database; +use Koha::DateUtils; +use Koha::Holds; use Koha::Illrequests; use Koha::Items; -use Koha::Patrons; -use Koha::Patron::Debarments; -use Koha::Database; use Koha::Libraries; -use Koha::Account::Lines; -use Koha::Holds; -use Koha::Account::Lines; -use Koha::Account::Offsets; -use Koha::Config::SysPrefs; -use Koha::Charges::Fees; -use Koha::Util::SystemPreferences; -use Koha::Checkouts::ReturnClaims; +use Koha::Patron::Debarments; +use Koha::Patrons; +use Koha::Plugins; use Koha::SearchEngine::Indexer; -use Carp; -use List::MoreUtils qw( uniq any ); -use Scalar::Util qw( looks_like_number ); -use Try::Tiny; -use Date::Calc qw( - Today - Today_and_Now - Add_Delta_YM - Add_Delta_DHMS - Date_to_Days - Day_of_Week - Add_Delta_Days -); +use Koha::Util::SystemPreferences; + use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); BEGIN { @@ -173,6 +175,7 @@ sub barcodedecode { my ($barcode, $filter) = @_; my $branch = C4::Context::mybranch(); $filter = C4::Context->preference('itemBarcodeInputFilter') unless $filter; + ($barcode) = Koha::Plugins->call('barcode_transform', 'item', $barcode ) || $barcode; $filter or return $barcode; # ensure filter is defined, else return untouched barcode if ($filter eq 'whitespace') { $barcode =~ s/\s//g; diff --git a/C4/ILSDI/Services.pm b/C4/ILSDI/Services.pm index dfe80c14f2..8892911fa6 100644 --- a/C4/ILSDI/Services.pm +++ b/C4/ILSDI/Services.pm @@ -34,6 +34,7 @@ use CGI qw ( -utf8 ); use DateTime; use C4::Auth; use Koha::DateUtils; +use Koha::Plugins; use Koha::Biblios; use Koha::Checkouts; @@ -642,6 +643,7 @@ sub GetServices { # Issuing management my $barcode = $item->barcode || ''; $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') ); + ($barcode) = Koha::Plugins->call('barcode_transform', 'item', $barcode ) || $barcode; if ($barcode) { my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $barcode ); diff --git a/C4/Items.pm b/C4/Items.pm index 430ca8e477..db6aefdd87 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -73,6 +73,7 @@ use Koha::SearchEngine; use Koha::SearchEngine::Indexer; use Koha::SearchEngine::Search; use Koha::Libraries; +use Koha::Plugins; =head1 NAME diff --git a/Koha/Item.pm b/Koha/Item.pm index 5c9d86e49a..9aaf7e13c1 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -89,6 +89,9 @@ sub store { $self->itype($self->biblio->biblioitem->itemtype); } + my ($transformed_barcode) = Koha::Plugins->call( 'barcode_transform', 'item', $self->barcode ) || $self->barcode; + $self->barcode($transformed_barcode); + my $today = dt_from_string; my $action = 'create'; diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index b8face6d22..670927592f 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -36,6 +36,7 @@ use Koha::ItemTypes; use Koha::Libraries; use Koha::Patrons; use Koha::SearchEngine::Indexer; +use Koha::Plugins; use List::MoreUtils qw/any/; use C4::Search; use Storable qw(thaw freeze); @@ -516,6 +517,9 @@ if ($op eq "additem") { my $addedolditem = TransformMarcToKoha( $record ); + my ( $new_barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $addedolditem->{'barcode'} ) || $addedolditem->{'barcode'}; + $addedolditem->{'barcode'} = $new_barcode; + # If we have to add or add & duplicate, we add the item if ( $add_submit || $add_duplicate_submit ) { diff --git a/circ/circulation.pl b/circ/circulation.pl index ee3878ca13..853625ca46 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -46,6 +46,7 @@ use Koha::AuthorisedValues; use Koha::CsvProfiles; use Koha::Patrons; use Koha::Patron::Debarments qw(GetDebarments); +use Koha::Plugins; use Koha::DateUtils; use Koha::Database; use Koha::BiblioFrameworks; @@ -165,6 +166,7 @@ for my $barcode ( @$barcodes ) { $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace $barcode = barcodedecode($barcode) if( $barcode && C4::Context->preference('itemBarcodeInputFilter')); + ( $barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $barcode ) || $barcode; } my $stickyduedate = $query->param('stickyduedate') || $session->param('stickyduedate'); diff --git a/circ/returns.pl b/circ/returns.pl index 116ac3c15e..d1548128bf 100755 --- a/circ/returns.pl +++ b/circ/returns.pl @@ -56,6 +56,7 @@ use Koha::DateUtils; use Koha::Holds; use Koha::Items; use Koha::Patrons; +use Koha::Plugins; my $query = CGI->new; @@ -114,6 +115,7 @@ foreach ( $query->param ) { # decode barcode ## Didn't we already decode them before passing them back last time?? $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace + ( $barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $barcode ) || $barcode; $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter')); ###################### @@ -243,6 +245,7 @@ if ($canceltransfer){ my $returnbranch; if ($barcode) { $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace + ( $barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $barcode ) || $barcode; $barcode = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter'); my $item = Koha::Items->find({ barcode => $barcode }); diff --git a/offline_circ/process_koc.pl b/offline_circ/process_koc.pl index ce2c6c5524..cb1be901a1 100755 --- a/offline_circ/process_koc.pl +++ b/offline_circ/process_koc.pl @@ -38,6 +38,7 @@ use Koha::UploadedFiles; use Koha::Account; use Koha::Checkouts; use Koha::Patrons; +use Koha::Plugins; use Date::Calc qw( Add_Delta_Days Date_to_Days ); @@ -246,6 +247,10 @@ sub kocIssueItem { my $circ = shift; $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter')); + + my ( $new_barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $circ->{barcode} ) || $circ->{barcode}; + $circ->{barcode} = $new_barcode; + my $branchcode = C4::Context->userenv->{branch}; my $patron = Koha::Patrons->find( { cardnumber => $circ->{cardnumber} } ); my $borrower = $patron->unblessed; @@ -326,6 +331,10 @@ sub kocIssueItem { sub kocReturnItem { my ( $circ ) = @_; $circ->{'barcode'} = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter')); + + my ( $new_barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $circ->{barcode} ) || $circ->{barcode}; + $circ->{barcode} = $new_barcode; + my $item = Koha::Items->find({ barcode => $circ->{barcode} }); my $biblio = $item->biblio; my $borrowernumber = _get_borrowernumber_from_barcode( $circ->{'barcode'} ); diff --git a/opac/sco/sco-main.pl b/opac/sco/sco-main.pl index 742f7f43ca..0a7a1fef6a 100755 --- a/opac/sco/sco-main.pl +++ b/opac/sco/sco-main.pl @@ -49,6 +49,7 @@ use Koha::Items; use Koha::Patrons; use Koha::Patron::Images; use Koha::Patron::Messages; +use Koha::Plugins; use Koha::Token; my $query = CGI->new; @@ -109,6 +110,8 @@ my ($op, $patronid, $patronlogin, $patronpw, $barcode, $confirmed, $newissues) = $query->param("newissues") || '', ); +( $barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $barcode ) || $barcode; + my @newissueslist = split /,/, $newissues; my $issuenoconfirm = 1; #don't need to confirm on issue. my $issuer = Koha::Patrons->find( $issuerid )->unblessed; diff --git a/t/db_dependent/Koha/Plugins/Plugins.t b/t/db_dependent/Koha/Plugins/Plugins.t index f49bd252fc..bf5c33c524 100755 --- a/t/db_dependent/Koha/Plugins/Plugins.t +++ b/t/db_dependent/Koha/Plugins/Plugins.t @@ -25,7 +25,7 @@ use File::Temp qw( tempdir tempfile ); use FindBin qw($Bin); use Module::Load::Conditional qw(can_load); use Test::MockModule; -use Test::More tests => 53; +use Test::More tests => 55; use C4::Context; use Koha::Database; @@ -181,6 +181,8 @@ ok( $plugin->can('opac_head'), 'Test plugin can opac_head' ); ok( $plugin->can('opac_js'), 'Test plugin can opac_js' ); ok( $plugin->can('intranet_head'), 'Test plugin can intranet_head' ); ok( $plugin->can('intranet_js'), 'Test plugin can intranet_js' ); +ok( $plugin->can('barcode_transform'), 'Test plugin can barcode_transform' ); +ok( $plugin->can('barcode_generate'), 'Test plugin can barcode_generate' ); ok( $plugin->can('configure'), 'Test plugin can configure' ); ok( $plugin->can('install'), 'Test plugin can install' ); ok( $plugin->can('upgrade'), 'Test plugin can upgrade' ); diff --git a/t/lib/Koha/Plugin/Test.pm b/t/lib/Koha/Plugin/Test.pm index 0a92967738..c3ae8c7f5b 100644 --- a/t/lib/Koha/Plugin/Test.pm +++ b/t/lib/Koha/Plugin/Test.pm @@ -93,6 +93,15 @@ sub intranet_js { return "Koha::Plugin::Test::intranet_js"; } +sub barcode_transform { + my ( $self, $type, $barcode ) = @_; + return "Koha::Plugin::Test::barcode_transform"; +} + +sub barcode_generate { + my ( $self, $type, $object ) +} + sub configure { my ( $self, $args ) = @_; return "Koha::Plugin::Test::configure";; diff --git a/tools/batchMod.pl b/tools/batchMod.pl index dca2e41ad4..bb67943384 100755 --- a/tools/batchMod.pl +++ b/tools/batchMod.pl @@ -45,6 +45,7 @@ use Koha::Items; use Koha::ItemTypes; use Koha::Patrons; use Koha::SearchEngine::Indexer; +use Koha::Plugins; my $input = CGI->new; my $dbh = C4::Context->dbh; @@ -402,6 +403,9 @@ if ($op eq "show"){ if ( my $list = $input->param('barcodelist') ) { my @barcodelist = grep /\S/, ( split /[$split_chars]/, $list ); @barcodelist = uniq @barcodelist; + + @barcodelist = map { ( Koha::Plugins->call( 'barcode_transform', 'item', $_ ) )[0] || $_ } @barcodelist; + # Note: adding lc for case insensitivity my %itemdata = map { lc($_->{barcode}) => $_->{itemnumber} } @{ Koha::Items->search({ barcode => \@barcodelist }, { columns => [ 'itemnumber', 'barcode' ] } )->unblessed }; @itemnumbers = map { exists $itemdata{lc $_} ? $itemdata{lc $_} : () } @barcodelist; diff --git a/tools/inventory.pl b/tools/inventory.pl index 632968219d..bf64b5ea81 100755 --- a/tools/inventory.pl +++ b/tools/inventory.pl @@ -42,6 +42,8 @@ use Koha::AuthorisedValues; use Koha::BiblioFrameworks; use Koha::ClassSources; use Koha::Items; +use Koha::Plugins; + use List::MoreUtils qw( none ); my $minlocation=$input->param('minlocation') || ''; @@ -180,6 +182,9 @@ if ( ($uploadbarcodes && length($uploadbarcodes) > 0) || ($barcodelist && length } for my $barcode (@uploadedbarcodes) { next unless $barcode; + + ($barcode) = Koha::Plugins->call('barcode_transform', 'item', $barcode ) || $barcode; + ++$lines_read; if (length($barcode)>$barcode_size) { $err_length += 1; -- 2.24.1 (Apple Git-126)