From dd5639e0b8f1e6d7762bfa3a6ff26bd91505c87d Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 11 Jun 2020 08:25:05 -0400 Subject: [PATCH] Bug 25712: Add plugin hooks to transform patron and 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 patron search and anywhere else you can scan a patron cardnumber, type in some cardnumbers but prefix them with A and postfix them with A or B, e.g. A12345A, A12345B 5) Note the letters are removed by Koha! 6) Try a cardnumber like X123456Y 7) Note Koha converts it to Z13456Z 8) Try an item barcode now with the same A A|B format from step 4 9) The item barcode should have the letters removed by Koha as well! --- C4/Circulation.pm | 2 ++ C4/ILSDI/Services.pm | 2 ++ C4/Items.pm | 1 + C4/SIP/Sip/MsgType.pm | 16 ++++++++++++++++ Koha/Item.pm | 3 +++ Koha/Patron.pm | 8 +++++++- Koha/Patron/Attribute.pm | 1 + cataloguing/additem.pl | 4 ++++ circ/circulation.pl | 3 +++ circ/returns.pl | 3 +++ members/memberentry.pl | 4 ++++ offline_circ/process_koc.pl | 9 +++++++++ opac/sco/sco-main.pl | 4 ++++ t/db_dependent/Koha/Plugins/Plugins.t | 4 +++- t/lib/Koha/Plugin/Test.pm | 9 +++++++++ tools/batchMod.pl | 4 ++++ tools/inventory.pl | 5 +++++ 17 files changed, 80 insertions(+), 2 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 7a3b21b903..934cf98c5e 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -59,6 +59,7 @@ use Koha::Config::SysPrefs; use Koha::Charges::Fees; use Koha::Util::SystemPreferences; use Koha::Checkouts::ReturnClaims; +use Koha::Plugins; use Carp; use List::MoreUtils qw( uniq any ); use Scalar::Util qw( looks_like_number ); @@ -173,6 +174,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 ); $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 5ebba3435d..07b00c3bdf 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; @@ -613,6 +614,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 ); if ($barcode) { my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $barcode ); diff --git a/C4/Items.pm b/C4/Items.pm index a162ac5dec..30d91f303f 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -72,6 +72,7 @@ use Koha::ItemTypes; use Koha::SearchEngine; use Koha::SearchEngine::Search; use Koha::Libraries; +use Koha::Plugins; =head1 NAME diff --git a/C4/SIP/Sip/MsgType.pm b/C4/SIP/Sip/MsgType.pm index a61cd7b716..dae7e70def 100644 --- a/C4/SIP/Sip/MsgType.pm +++ b/C4/SIP/Sip/MsgType.pm @@ -19,6 +19,7 @@ use CGI qw ( -utf8 ); use C4::Auth qw(&check_api_auth); use Koha::Patron::Attributes; +use Koha::Plugins; use Koha::Items; use UNIVERSAL::can; @@ -519,6 +520,7 @@ sub handle_checkout { $fields = $self->{fields}; $patron_id = $fields->{ (FID_PATRON_ID) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); $item_id = $fields->{ (FID_ITEM_ID) }; my $fee_ack = $fields->{ (FID_FEE_ACK) }; @@ -732,6 +734,8 @@ sub handle_block_patron { $patron_id = $fields->{ (FID_PATRON_ID) }; $terminal_pwd = $fields->{ (FID_TERMINAL_PWD) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + # Terminal passwords are different from account login # passwords, but I have no idea what to do with them. So, # I'll just ignore them for now. @@ -956,6 +960,8 @@ sub handle_patron_info { $start = $fields->{ (FID_START_ITEM) }; $end = $fields->{ (FID_END_ITEM) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + $patron = $ils->find_patron($patron_id); $resp = (PATRON_INFO_RESP); @@ -1113,6 +1119,8 @@ sub handle_fee_paid { $fee_id = $fields->{ (FID_FEE_ID) }; $trans_id = $fields->{ (FID_TRANSACTION_ID) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + $ils->check_inst_id( $inst_id, "handle_fee_paid" ); my $pay_result = $ils->pay_fee( $patron_id, $patron_pwd, $fee_amt, $fee_type, $pay_type, $fee_id, $trans_id, $currency, $is_writeoff, $disallow_overpayment, $register_id ); @@ -1301,6 +1309,8 @@ sub handle_patron_enable { $patron_id = $fields->{ (FID_PATRON_ID) }; $patron_pwd = $fields->{ (FID_PATRON_PWD) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + siplog( "LOG_DEBUG", "handle_patron_enable: patron_id: '%s', patron_pwd: '%s'", $patron_id, $patron_pwd ); $patron = $ils->find_patron($patron_id); @@ -1364,6 +1374,8 @@ sub handle_hold { $title_id = $fields->{ (FID_TITLE_ID) } || ''; $fee_ack = $fields->{ (FID_FEE_ACK) } || 'N'; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + if ( $hold_mode eq '+' ) { $status = $ils->add_hold( $patron_id, $patron_pwd, $item_id, $title_id, $expiry_date, $pickup_locn, $hold_type, $fee_ack ); } elsif ( $hold_mode eq '-' ) { @@ -1429,6 +1441,8 @@ sub handle_renew { $item_props = $fields->{ (FID_ITEM_PROPS) }; $fee_ack = $fields->{ (FID_FEE_ACK) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + $status = $ils->renew( $patron_id, $patron_pwd, $item_id, $title_id, $no_block, $nb_due_date, $third_party, $item_props, $fee_ack ); $patron = $status->patron; @@ -1510,6 +1524,8 @@ sub handle_renew_all { $terminal_pwd = $fields->{ (FID_TERMINAL_PWD) }; $fee_ack = $fields->{ (FID_FEE_ACK) }; + ($patron_id) = Koha::Plugins->call('barcode_transform', 'patron', $patron_id ); + $status = $ils->renew_all( $patron_id, $patron_pwd, $fee_ack ); $resp .= $status->ok ? '1' : '0'; diff --git a/Koha/Item.pm b/Koha/Item.pm index 9560a567cb..c403230775 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -87,6 +87,9 @@ sub store { $self->itype($self->biblio->biblioitem->itemtype); } + my ($transformed_barcode) = Koha::Plugins->call( 'barcode_transform', 'item', $self->barcode ); + $self->barcode($transformed_barcode); + my $today = dt_from_string; unless ( $self->in_storage ) { #AddItem unless ( $self->permanent_location ) { diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 5436ccc448..f1d26c8235 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -110,7 +110,10 @@ Autogenerate next cardnumber from highest value found in database sub fixup_cardnumber { my ( $self ) = @_; - my $max = Koha::Patrons->search({ + + my ( $max ) = Koha::Plugins->call( 'barcode_generate', 'patron', $self ); + + $max ||= Koha::Patrons->search({ cardnumber => {-regexp => '^-?[0-9]+$'} }, { select => \'CAST(cardnumber AS SIGNED)', @@ -197,6 +200,9 @@ sub store { $self->trim_whitespaces; + my ( $new_cardnumber ) = Koha::Plugins->call( 'barcode_transform', 'patron', $self->cardnumber ); + $self->cardnumber( $new_cardnumber ); + # Set surname to uppercase if uppercasesurname is true $self->surname( uc($self->surname) ) if C4::Context->preference("uppercasesurnames"); diff --git a/Koha/Patron/Attribute.pm b/Koha/Patron/Attribute.pm index 5afd674149..7ab07ca17d 100644 --- a/Koha/Patron/Attribute.pm +++ b/Koha/Patron/Attribute.pm @@ -20,6 +20,7 @@ use Modern::Perl; use Koha::Database; use Koha::Exceptions::Patron::Attribute; use Koha::Patron::Attribute::Types; +use Koha::Plugins; use Koha::AuthorisedValues; use base qw(Koha::Object); diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index b0ce8b58c5..6246fa47e1 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -35,6 +35,7 @@ use Koha::Items; use Koha::ItemTypes; use Koha::Libraries; use Koha::Patrons; +use Koha::Plugins; use List::MoreUtils qw/any/; use C4::Search; use Storable qw(thaw freeze); @@ -486,6 +487,9 @@ if ($op eq "additem") { $record = _increment_barcode($record, $frameworkcode); } + my ( $new_barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $addedolditem->{'barcode'} ); + $addedolditem->{'barcode'} = $new_barcode; + my $addedolditem = TransformMarcToKoha( $record ); # If we have to add or add & duplicate, we add the item diff --git a/circ/circulation.pl b/circ/circulation.pl index 5ec80c8f15..2164f636a1 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; @@ -166,6 +167,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 ); } my $stickyduedate = $query->param('stickyduedate') || $session->param('stickyduedate'); @@ -227,6 +229,7 @@ if ( @$barcodes == 0 && $charges eq 'yes' ) { # my $message; if ($findborrower) { + ( $findborrower ) = Koha::Plugins->call( 'barcode_transform', 'patron', $findborrower ); my $patron = Koha::Patrons->find( { cardnumber => $findborrower } ); if ( $patron ) { $borrowernumber = $patron->borrowernumber; diff --git a/circ/returns.pl b/circ/returns.pl index e1bce3c3f1..5a029d44aa 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 = new CGI; @@ -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 = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter')); ###################### @@ -246,6 +248,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 = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter'); my $item = Koha::Items->find({ barcode => $barcode }); diff --git a/members/memberentry.pl b/members/memberentry.pl index cfdc06032e..86c959799d 100755 --- a/members/memberentry.pl +++ b/members/memberentry.pl @@ -45,6 +45,7 @@ use Koha::Patron::Attribute::Types; use Koha::Patron::Categories; use Koha::Patron::HouseboundRole; use Koha::Patron::HouseboundRoles; +use Koha::Plugins; use Koha::Token; use Email::Valid; use Koha::SMS::Providers; @@ -324,6 +325,9 @@ if ($op eq 'save' || $op eq 'insert'){ # If the cardnumber is blank, treat it as null. $newdata{'cardnumber'} = undef if $newdata{'cardnumber'} =~ /^\s*$/; + my ( $new_barcode ) = Koha::Plugins->call( 'barcode_transform', 'patron', $newdata{'cardnumber'} ); + $newdata{'cardnumber'} = $new_barcode; + if (my $error_code = checkcardnumber($newdata{cardnumber},$newdata{borrowernumber})){ push @errors, $error_code == 1 ? 'ERROR_cardnumber_already_exists' diff --git a/offline_circ/process_koc.pl b/offline_circ/process_koc.pl index 935440b55b..138f8d7c7f 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 ); @@ -247,6 +248,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} = $new_barcode; + my $branchcode = C4::Context->userenv->{branch}; my $patron = Koha::Patrons->find( { cardnumber => $circ->{cardnumber} } ); my $borrower = $patron->unblessed; @@ -327,6 +332,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} = $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 83a37aca46..d2c1bb7b86 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 = new CGI; @@ -110,6 +111,8 @@ my ($op, $patronid, $patronlogin, $patronpw, $barcode, $confirmed, $newissues) = $query->param("newissues") || '', ); +( $barcode ) = Koha::Plugins->call( 'barcode_transform', 'item', $barcode ); + my @newissueslist = split /,/, $newissues; my $issuenoconfirm = 1; #don't need to confirm on issue. my $issuer = Koha::Patrons->find( $issuerid )->unblessed; @@ -122,6 +125,7 @@ if (C4::Context->preference('SelfCheckoutByLogin') && !$patronid) { my ( $borrower, $patron ); if ( $patronid ) { + ( $patronid ) = Koha::Plugins->call( 'barcode_transform', 'patron', $patronid ); $patron = Koha::Patrons->find( { cardnumber => $patronid } ); $borrower = $patron->unblessed if $patron; } diff --git a/t/db_dependent/Koha/Plugins/Plugins.t b/t/db_dependent/Koha/Plugins/Plugins.t index e6a353ceee..0f1d184582 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 => 52; +use Test::More tests => 54; use C4::Context; use Koha::Database; @@ -175,6 +175,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_create'), 'Test plugin can barcode_create' ); 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 8036c1fd5e..22dbffb8d1 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 91ede79b1e..55fcfc58d3 100755 --- a/tools/batchMod.pl +++ b/tools/batchMod.pl @@ -44,6 +44,7 @@ use Koha::DateUtils; use Koha::Items; use Koha::ItemTypes; use Koha::Patrons; +use Koha::Plugins; my $input = new CGI; my $dbh = C4::Context->dbh; @@ -364,6 +365,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', $barcode ) )[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 13b7a538a5..3474a85131 100755 --- a/tools/inventory.pl +++ b/tools/inventory.pl @@ -41,6 +41,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') || ''; @@ -171,6 +173,9 @@ if ( $uploadbarcodes && length($uploadbarcodes) > 0 ) { } for my $barcode (@uploadedbarcodes) { next unless $barcode; + + ($barcode) = Koha::Plugins->call('barcode_transform', 'item', $barcode ); + ++$lines_read; if (length($barcode)>$barcode_size) { $err_length += 1; -- 2.24.1 (Apple Git-126)