Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implement barcode-prefix functionality. See Koha RFC 'Barcode Prefixes'

  Add barcodeprefixes (items and patrons) to branches table and sysprefs for barcodelengths. See Koha RFC 'Barcode Prefixes'

  Relies on the system preference {item,patron}barcodelength to determine whether it should try to add the prefix.
  Still unsafe to allow auto-prefixing of barcode on item edit, since we can't be sure that an item mod isn't just a status change,
  and that status changes are all only passing an item hash with the fields to be modified (i.e. the barcode isn't always supplied).

  Add a FIXME: Since the interface allows the user to reassign a patron's home library,
  the auto-calc of next cardnumber needs a new ajax function to update the autocalculated barcode
  if the user alters a patron's home library.  This is not yet implemented.

  Add script to dynamically generate barcode image for printing on transfer jacket sleeves.
  Adds GD::Barcode dependency ( but only for the new script; does not add dependency to any extant code ).

  Update hold-transfer-slip with more information and additional markup to allow for css customization.
  • Loading branch information...
commit edf3c53fc8f8bd95da09712ad6d9ddba521602ef 1 parent d06e6d4
Ryan Higgins authored
View
64 C4/Circulation.pm
@@ -128,14 +128,20 @@ Also deals with stocktaking.
=over 4
=item Generic filter function for barcode string.
-Called on every circ if the System Pref itemBarcodeInputFilter is set.
+Called on every circ if either System Pref B<itemBarcodeInputFilter> or B<itembarcodelength> is set,
+applying one or both modifications as appropriate.
+
Will do some manipulation of the barcode for systems that deliver a barcode
to circulation.pl that differs from the barcode stored for the item.
For proper functioning of this filter, calling the function on the
correct barcode string (items.barcode) should return an unaltered barcode.
+Per branch barcode prefixes are inserted AFTER the filter function is applied
+to fix the barcode at branches.itembarcodelength characters IFF
+C<C4::Context->preference('itembarcodelength')> exists and is longer than C<length($barcode)>.
+
The optional $filter argument is to allow for testing or explicit
-behavior that ignores the System Pref. Valid values are the same as the
+behavior that ignores the System Pref. Valid values are the same as the
System Pref options.
=back
@@ -148,25 +154,41 @@ System Pref options.
sub barcodedecode {
my ($barcode, $filter) = @_;
$filter = C4::Context->preference('itemBarcodeInputFilter') unless $filter;
- $filter or return $barcode; # ensure filter is defined, else return untouched barcode
- if ($filter eq 'whitespace') {
- $barcode =~ s/\s//g;
- } elsif ($filter eq 'cuecat') {
- chomp($barcode);
- my @fields = split( /\./, $barcode );
- my @results = map( decode($_), @fields[ 1 .. $#fields ] );
- ($#results == 2) and return $results[2];
- } elsif ($filter eq 'T-prefix') {
- if ($barcode =~ /^[Tt](\d)/) {
- (defined($1) and $1 eq '0') and return $barcode;
- $barcode = substr($barcode, 2) + 0; # FIXME: probably should be substr($barcode, 1)
- }
- return sprintf("T%07d", $barcode);
- # FIXME: $barcode could be "T1", causing warning: substr outside of string
- # Why drop the nonzero digit after the T?
- # Why pass non-digits (or empty string) to "T%07d"?
- }
- return $barcode; # return barcode, modified or not
+
+ my $filter_dispatch = {
+ 'whitespace' => sub {
+ $barcode =~ s/\s//g;
+ return $barcode;
+ },
+ 'T-prefix' => sub {
+ if ($barcode =~ /^[Tt](\d)/) {
+ (defined($1) and $1 eq '0') and return $barcode;
+ $barcode = substr($barcode, 2) + 0; # FIXME: probably should be substr($barcode, 1)
+ }
+ return sprintf("T%07d", $barcode);
+ # FIXME: $barcode could be "T1", causing warning: substr outside of string
+ # Why drop the nonzero digit after the T?
+ # Why pass non-digits (or empty string) to "T%07d"?
+ },
+ 'cuecat' => sub {
+ chomp($barcode);
+ my @fields = split( /\./, $barcode );
+ my @results = map( decode($_), @fields[ 1 .. $#fields ] );
+ if ( $#results == 2 ) {
+ return $results[2];
+ } else {
+ return $barcode;
+ }
+ },
+ };
+ my $filtered = ($filter && exists($filter_dispatch->{$filter})) ? $filter_dispatch->{$filter}() : $barcode;
+ if(C4::Context->preference('itembarcodelength') && (length($filtered) < C4::Context->preference('itembarcodelength'))) {
+ my $prefix = GetBranchDetail(C4::Context->userenv->{'branch'})->{'itembarcodeprefix'} ;
+ my $padding = C4::Context->preference('itembarcodelength') - length($prefix) - length($filtered) ;
+ # FIXME : error check?
+ $filtered = $prefix . '0' x $padding . $filtered if($padding >= 0) ;
+ }
+ return $filtered || $barcode ;
}
=head2 decode
View
14 C4/Items.pm
@@ -218,7 +218,7 @@ sub AddItem {
my $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
$sth->execute( $item->{'biblionumber'} );
($item->{'biblioitemnumber'}) = $sth->fetchrow;
-
+ _check_itembarcode($item) if(C4::Context->preference('itembarcodelength')) ;
_set_defaults_for_add($item);
_set_derived_columns_for_add($item);
$item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
@@ -324,6 +324,7 @@ sub AddItemBatchFromMarc {
next ITEMFIELD;
}
+ _check_itembarcode($item) if(C4::Context->preference('itembarcodelength')) ;
_set_defaults_for_add($item);
_set_derived_columns_for_add($item);
my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
@@ -469,6 +470,11 @@ sub ModItem {
};
$item->{'itemnumber'} = $itemnumber or return undef;
+
+ # FIXME : ModItem is called on status mods, not just item edits.
+ # status mods should be separated into a different function, so we can safely call _check_itembarcode.
+ # _check_itembarcode($item) if(C4::Context->preference('itembarcodelength')) ;
+
_set_derived_columns_for_mod($item);
_do_column_fixes_for_mod($item);
# FIXME add checks
@@ -608,7 +614,7 @@ sub DelItem {
Given a hashref containing item fields, determine if it can be
inserted or updated in the database. Specifically, checks for
database integrity issues, and returns a hash containing any
-of the following keys, if applicable.
+of the following keys, if applicable.
=over 2
@@ -642,7 +648,7 @@ sub CheckItemPreSave {
my $existing_itemnumber = GetItemnumberFromBarcode($item_ref->{'barcode'});
if ($existing_itemnumber) {
if (!exists $item_ref->{'itemnumber'} # new item
- or $item_ref->{'itemnumber'} != $existing_itemnumber) { # existing item
+ or $item_ref->{'itemnumber'} != $existing_itemnumber) { # existing item
$errors{'duplicate_barcode'} = $item_ref->{'barcode'};
}
}
@@ -2241,7 +2247,7 @@ sub _parse_unlinked_item_subfields_from_xml {
=back
Modifies item barcode value to include prefix defined in branches.itembarcodeprefix
-IFF the system preference enforce_barcode_prefix is true.
+if the length is less than the syspref itembarcodelength .
=cut
sub _check_itembarcode($) {
View
102 C4/Members.pm
@@ -24,6 +24,7 @@ use C4::Dates qw(format_date_in_iso);
use Digest::MD5 qw(md5_base64);
use Date::Calc qw/Today Add_Delta_YM/;
use C4::Log; # logaction
+use C4::Branch qw(GetBranchDetail);
use C4::Overdues;
use C4::Reserves;
use C4::Accounts;
@@ -171,11 +172,12 @@ sub SearchMember {
# this is used by circulation everytime a new borrowers cardnumber is scanned
# so we can check an exact match first, if that works return, otherwise do the rest
+ my $cardnum = _prefix_cardnum($searchstring);
$query = "SELECT * FROM borrowers
LEFT JOIN categories ON borrowers.categorycode=categories.categorycode
";
my $sth = $dbh->prepare("$query WHERE cardnumber = ?");
- $sth->execute($searchstring);
+ $sth->execute($cardnum);
my $data = $sth->fetchall_arrayref({});
if (@$data){
return ( scalar(@$data), $data );
@@ -601,6 +603,12 @@ sub ModMember {
$data{password} = md5_base64($data{password});
}
}
+ # modify cardnumber if necessary.
+ if(C4::Context->preference('patronbarcodelength') && exists($data{'cardnumber'})){
+ $data{'cardnumber'} = _prefix_cardnum($data{'cardnumber'});
+ # TODO : generate error if cardnumber does not match barcode schema,
+ # or length not sufficient to prefix without corrupting input string.
+ }
my @badkeys;
foreach (keys %data) {
next if ($_ eq 'borrowernumber' or $_ eq 'flags');
@@ -647,7 +655,8 @@ sub AddMember {
my $dbh = C4::Context->dbh;
$data{'userid'} = '' unless $data{'password'};
$data{'password'} = md5_base64( $data{'password'} ) if $data{'password'};
-
+ $data{'cardnumber'} = _prefix_cardnum($data{'cardnumber'}) if(C4::Context->preference('patronbarcodelength'));
+
# WE SHOULD NEVER PASS THIS SUBROUTINE ANYTHING OTHER THAN ISO DATES
# IF YOU UNCOMMENT THESE LINES YOU BETTER HAVE A DARN COMPELLING REASON
# $data{'dateofbirth'} = format_date_in_iso( $data{'dateofbirth'} );
@@ -798,6 +807,7 @@ sub changepassword {
=head2 fixup_cardnumber
+get next available cardnumber.
Warning: The caller is responsible for locking the members table in write
mode, to avoid database corruption.
@@ -806,22 +816,20 @@ mode, to avoid database corruption.
use vars qw( @weightings );
my @weightings = ( 8, 4, 6, 3, 5, 2, 1 );
-sub fixup_cardnumber ($) {
- my ($cardnumber) = @_;
+sub fixup_cardnumber {
+ my ($cardnumber, $branch) = @_;
my $autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0;
# Find out whether member numbers should be generated
# automatically. Should be either "1" or something else.
# Defaults to "0", which is interpreted as "no".
- # if ($cardnumber !~ /\S/ && $autonumber_members) {
($autonumber_members) or return $cardnumber;
my $checkdigit = C4::Context->preference('checkdigit');
my $dbh = C4::Context->dbh;
if ( $checkdigit and $checkdigit eq 'katipo' ) {
# if checkdigit is selected, calculate katipo-style cardnumber.
- # otherwise, just use the max()
# purpose: generate checksum'd member numbers.
# We'll assume we just got the max value of digits 2-8 of member #'s
# from the database and our job is to increment that by one,
@@ -860,24 +868,40 @@ sub fixup_cardnumber ($) {
# whether the string is numeric or not.
# FIXME : This needs to be pulled out into an ajax function, since the interface allows on-the-fly changing of patron home library.
#
- my $query = "select max(borrowers.cardnumber) from borrowers ";
- my @bind;
- my $cardlength = C4::Context->preference('patronbarcodelength');
- my $firstnumber = 0;
- if($branch->{'patronbarcodeprefix'} && $cardlength) {
- my $minrange = 10**($cardlength-length($branch->{'patronbarcodeprefix'}) );
- $query .= " WHERE cardnumber BETWEEN ? AND ?";
- $query .= " AND length(cardnumber) = ?";
- $firstnumber = $branch->{'patronbarcodeprefix'} .substr(sprintf("%s",$minrange), 1) ;
- @bind = ($firstnumber , $branch->{'patronbarcodeprefix'} . sprintf( "%s",$minrange - 1),$cardlength ) ;
- }
- my $sth= $dbh->prepare($query);
- $sth->execute(@bind);
- my ($result) = $sth->fetchrow;
- $sth->finish;
- $cardnumber = $result + 1;
- }
- }
+ my $query = "select max(borrowers.cardnumber) from borrowers ";
+ my @bind;
+ my $cardlength = C4::Context->preference('patronbarcodelength');
+ my $firstnumber = 0;
+ if($branch->{'patronbarcodeprefix'} && $cardlength) {
+ my $minrange = 10**($cardlength-length($branch->{'patronbarcodeprefix'}) );
+ $query .= " WHERE cardnumber BETWEEN ? AND ?";
+ $query .= " AND length(cardnumber) = ?";
+ $firstnumber = $branch->{'patronbarcodeprefix'} .substr(sprintf("%s",$minrange), 1) ;
+ @bind = ($firstnumber , $branch->{'patronbarcodeprefix'} . sprintf( "%s",$minrange - 1),$cardlength ) ;
+ }
+ my $sth= $dbh->prepare($query);
+ $sth->execute(@bind);
+ my ($result) = $sth->fetchrow;
+ $sth->finish;
+ if($result) {
+ $result =~ s/^$branch->{'patronbarcodeprefix'}//;
+ my $cnt = 0;
+ while ( $result =~ /([a-zA-Z]*[0-9]*)\z/ ) { # use perl's magical stringcrement behavior (++).
+ my $incrementable = $1;
+ $incrementable++;
+ if ( length($incrementable) > length($1) ) { # carry a digit to next incrementable fragment
+ $cardnumber = substr($incrementable,1) . $cardnumber;
+ $result = $`;
+ } else {
+ $cardnumber = $branch->{'patronbarcodeprefix'} . $` . $incrementable . $cardnumber ;
+ last;
+ }
+ last if(++$cnt>10);
+ }
+ } else {
+ $cardnumber = ++$firstnumber ;
+ }
+ }
return $cardnumber; # just here as a fallback/reminder
}
@@ -2053,6 +2077,36 @@ sub DebarMember {
}
+=head2 _prefix_cardnum
+
+=over 4
+
+$cardnum = _prefix_cardnum($cardnum,$branchcode);
+
+If a system-wide barcode length is defined, and a prefix defined for the passed branch or the user's branch,
+modify the barcode by prefixing and padding.
+
+=back
+=cut
+
+sub _prefix_cardnum{
+ my ($cardnum,$branchcode) = @_;
+
+ if(C4::Context->preference('patronbarcodelength') && (length($cardnum) < C4::Context->preference('patronbarcodelength'))) {
+ #if we have a system-wide cardnum length and a branch prefix, prepend the prefix.
+ if( ! $branchcode && defined(C4::Context->userenv) ) {
+ $branchcode = C4::Context->userenv->{'branch'};
+ }
+ return $cardnum unless $branchcode;
+ my $branch = GetBranchDetail( $branchcode );
+ return $cardnum unless( defined($branch) && defined($branch->{'patronbarcodeprefix'}) );
+ my $prefix = $branch->{'patronbarcodeprefix'} ;
+ my $padding = C4::Context->preference('patronbarcodelength') - length($prefix) - length($cardnum) ;
+ $cardnum = $prefix . '0' x $padding . $cardnum if($padding >= 0) ;
+ }
+ return $cardnum;
+}
+
END { } # module clean-up code here (global destructor)
1;
View
2  C4/Reserves.pm
@@ -1000,7 +1000,7 @@ sub GetReserveInfo {
cardnumber, city, zipcode,
biblio.title, biblio.author,
items.holdingbranch, items.itemcallnumber, items.itemnumber,
- barcode, notes
+ homebranch, barcode, notes
FROM reserves left join items
ON items.itemnumber=reserves.itemnumber ,
borrowers, biblio
View
7 C4/Schema/Result/Branches.pm
@@ -75,6 +75,13 @@ __PACKAGE__->add_columns(
is_nullable => 1,
size => 100,
},
+ "itembarcodeprefix",
+ {
+ data_type => "VARCHAR",
+ default_value => undef,
+ is_nullable => 1,
+ size => 10,
+ },
"patronbarcodeprefix",
{
data_type => "VARCHAR",
View
28 admin/branches.pl
@@ -67,11 +67,27 @@ =head1 branches.pl
debug => 1,
}
);
-$template->param(
- script_name => $script_name,
- action => $script_name,
+if ($op) {
+ $template->param(
+ script_name => $script_name,
+ $op => 1
+ ); # we show only the TMPL_VAR names $op
+}
+else {
+ $template->param(
+ script_name => $script_name,
+ else => 1
+ ); # we show only the TMPL_VAR names $op
+}
+$template->param( action => $script_name );
+
+#FIXME : this script needs significant revision to remove presentation-layer logic, printers, etc.
+
+# template params to pass regardless of user action:
+
+$template->param( itembarcodelength => C4::Context->preference('itembarcodelength'),
+ patronbarcodelength => C4::Context->preference('patronbarcodelength'),
);
-$template->param( ($op || 'else') => 1 );
if ( $op eq 'add' ) {
@@ -217,7 +233,9 @@ sub editbranchform {
branchphone => $data->{'branchphone'},
branchfax => $data->{'branchfax'},
branchemail => $data->{'branchemail'},
- branchip => $data->{'branchip'}
+ branchip => $data->{'branchip'},
+ itembarcodeprefix => $data->{'itembarcodeprefix'},
+ patronbarcodeprefix => $data->{'patronbarcodeprefix'},
);
}
View
2  admin/systempreferences.pl
@@ -92,6 +92,8 @@ =head1 systempreferences.pl
$tabsysprefs{noItemTypeImages} = "Admin";
$tabsysprefs{OPACBaseURL} = "Admin";
$tabsysprefs{GranularPermissions} = "Admin";
+$tabsysprefs{itembarcodelength} = "Admin";
+$tabsysprefs{patronbarcodelength} = "Admin";
# Authorities
$tabsysprefs{authoritysep} = "Authorities";
View
51 circ/barcode-img.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl
+
+
+# Copyright 2008 LibLime
+#
+# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+
+use strict;
+use C4::Context;
+use CGI;
+use CGI::Session;
+use C4::Auth qw/check_cookie_auth/;
+use CGI::Cookie; # need to check cookies before having CGI parse the POST request
+use GD::Barcode;
+
+my $input = new CGI;
+my %cookies = fetch CGI::Cookie;
+my ($auth_status, $sessionID) = check_cookie_auth($cookies{'CGISESSID'}->value, { circulation => 1 });
+
+if ($auth_status ne "ok") {
+ my $reply = CGI->new("");
+ print $reply->header(-type => 'text/html'); print "{}";
+ exit 0;
+}
+my $barcode = $input->param('barcode');
+
+my $reply = CGI->new('');
+#FIXME: Allow setting barcode type here.
+my $oGdBar = GD::Barcode->new('Code39', $barcode );
+
+if($oGdBar && $barcode) {
+ print $reply->header(-type => 'image/png');
+ print $oGdBar->plot->png;
+} else {
+ print $reply->header(-type => 'text/html');
+ print $GD::Barcode::errStr;
+}
+exit 0;
View
2  circ/circulation.pl
@@ -109,7 +109,7 @@
my $barcode = $query->param('barcode') || '';
$barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
-$barcode = barcodedecode($barcode) if( $barcode && C4::Context->preference('itemBarcodeInputFilter'));
+$barcode = barcodedecode($barcode) if( $barcode && (C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength')));
my $stickyduedate = $query->param('stickyduedate') || $session->param('stickyduedate');
my $duedatespec = $query->param('duedatespec') || $session->param('stickyduedate');
my $issueconfirmed = $query->param('issueconfirmed');
View
16 circ/hold-transfer-slip.pl
@@ -52,14 +52,18 @@ BEGIN
my $reserveinfo = GetReserveInfo($borrowernumber,$biblionumber );
my $pulldate = C4::Dates->new();
$reserveinfo->{'pulldate'} = $pulldate->output();
-$reserveinfo->{'branchname'} = GetBranchName($reserveinfo->{'branchcode'});
+$reserveinfo->{'pickup_library'} = GetBranchName($reserveinfo->{'branchcode'});
+$reserveinfo->{'owning_library'} = GetBranchName($reserveinfo->{'homebranch'});
+$reserveinfo->{'current_library'} = GetBranchName($reserveinfo->{'holdingbranch'});
+
$reserveinfo->{'transferrequired'} = $transfer;
-$template->param( reservedata => [ $reserveinfo ] ,
- );
+# If we have an itembarcodeprefix and we're transferring the item, send
+# item barcode to template for potential barcode image generation.
+if($transfer && C4::Context->preference('itembarcodelength') ) {
+ $reserveinfo->{'barcode-img'} = 1;
+}
+$template->param( reservedata => [ $reserveinfo ] );
output_html_with_http_headers $input, $cookie, $template->output;
-
-
-
View
7 circ/returns.pl
@@ -97,8 +97,8 @@ =head1 returns.pl
my $borrowernumber = $query->param("bn-$counter");
$counter++;
- # decode barcode ## Didn't we already decode them before passing them back last time??
- $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter'));
+ # decode barcode
+ $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength'));
######################
#Are these lines still useful ?
@@ -177,7 +177,8 @@ =head1 returns.pl
# actually return book and prepare item table.....
if ($barcode) {
- $barcode = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter');
+
+ $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength'));
$itemnumber = GetItemnumberFromBarcode($barcode);
( $returned, $messages, $issueinformation, $borrower ) =
View
3  installer/data/mysql/en/mandatory/sysprefs.sql
@@ -42,6 +42,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IssueLog',1,'If ON, log checkout activity',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IssuingInProcess',0,'If ON, disables fines if the patron is issuing item that accumulate debt',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itemcallnumber','082ab','The MARC field/subfield that is used to calculate the itemcallnumber (Dewey would be 082ab or 092ab; LOC would be 050ab or 090ab) could be 852hi from an item record',NULL,'free');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itembarcodelength','','Number of characters in system-wide barcode schema (item barcodes).','','Integer');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('DefaultClassificationSource','ddc','Default classification scheme used by the collection. E.g., Dewey, LCC, etc.', NULL,'ClassSources');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('KohaAdminEmailAddress','root@localhost','Define the email address where patron modification requests are sent','','free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('kohaspsuggest','','Track search queries, turn on by defining host:dbname:user:pass','','');
@@ -79,6 +80,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacTopissue',0,'If ON, enables the \'most popular items\' link on OPAC. Warning, this is an EXPERIMENTAL feature, turning ON may overload your server',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserjs','','Define custom javascript for inclusion in OPAC','70|10','Textarea');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserlogin',1,'Enable or disable display of user login features',NULL,'YesNo');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).','','Integer');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronimages',0,'Enable patron images for the Staff Client',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('printcirculationslips',1,'If ON, enable printing circulation receipts','','YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('RequestOnOpac',1,'If ON, globally enables patron holds on OPAC',NULL,'YesNo');
@@ -147,6 +149,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('globalDueDate','','If set, allows a global static due date for all checkouts','10','free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ceilingDueDate','','If set, date due will not be past this date. Enter date according to the dateformat System Preference',NULL,'free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itemBarcodeInputFilter','','If set, allows specification of a item barcode input filter','whitespace|T-prefix|cuecat','Choice');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).',NULL,'Integer');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('singleBranchMode',0,'Operate in Single-branch mode, hide branch selection in the OPAC',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('URLLinkText','','Text to display as the link anchor in the OPAC',NULL,'free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACSubscriptionDisplay','economical','Specify how to display subscription information in the OPAC','economical|off|full','Choice');
View
2  installer/data/mysql/fr-FR/1-Obligatoire/unimarc_standard_systemprefs.sql
@@ -45,6 +45,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('isbd', '#200|<h2>Titre : |{200a}{. 200c}{ : 200e}{200d}{. 200h}{. 200i}|</h2>\r\n#500|<label class="ipt">Autres titres : </label>|{500a}{. 500i}{. 500h}{. 500m}{. 500q}{. 500k}<br/>|\r\n#517|<label class="ipt"> </label>|{517a}{ : 517e}{. 517h}{, 517i}<br/>|\r\n#541|<label class="ipt"> </label>|{541a}{ : 541e}<br/>|\r\n#200||<label class="ipt">Auteurs : </label><br/>|\r\n#700||<a href="opac-search.pl?op=do_search&marclist=7009&operator==&type=intranet&value={7009}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{700c}{ 700b}{ 700a}{ 700d}{ (700f)}{. 7004}<br/>|\r\n#701||<a href="opac-search.pl?op=do_search&marclist=7009&operator==&type=intranet&value={7019}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{701c}{ 701b}{ 701a}{ 701d}{ (701f)}{. 7014}<br/>|\r\n#702||<a href="opac-search.pl?op=do_search&marclist=7009&operator==&type=intranet&value={7029}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{702c}{ 702b}{ 702a}{ 702d}{ (702f)}{. 7024}<br/>|\r\n#710||<a href="opac-search.pl?op=do_search&marclist=7109&operator==&type=intranet&value={7109}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{710a}{ (710c)}{. 710b}{ : 710d}{ ; 710f}{ ; 710e}<br/>|\r\n#711||<a href="opac-search.pl?op=do_search&marclist=7109&operator==&type=intranet&value={7119}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{711a}{ (711c)}{. 711b}{ : 711d}{ ; 711f}{ ; 711e}<br/>|\r\n#712||<a href="opac-search.pl?op=do_search&marclist=7109&operator==&type=intranet&value={7129}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur l''auteur"></a>{712a}{ (712c)}{. 712b}{ : 712d}{ ; 712f}{ ; 712e}<br/>|\r\n#210|<label class="ipt">Lieu d''édition : </label>|{ 210a}<br/>|\r\n#210|<label class="ipt">Editeur : </label>|{ 210c}<br/>|\r\n#210|<label class="ipt">Date d''édition : </label>|{ 210d}<br/>|\r\n#215|<label class="ipt">Description : </label>|{215a}{ : 215c}{ ; 215d}{ + 215e}|<br/>\r\n#225|<label class="ipt">Collection :</label>|<a href="opac-search.pl?op=do_search&marclist=225a&operator==&type=intranet&value={225a}"> <img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Chercher sur {225a}"></a>{ (225a}{ = 225d}{ : 225e}{. 225h}{. 225i}{ / 225f}{, 225x}{ ; 225v}|)<br/>\r\n#200||<label class="ipt">Sujets : </label><br/>|\r\n#600||<a href="opac-search.pl?op=do_search&marclist=6009&operator==&type=intranet&value={6009}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6009}"></a>{ 600c}{ 600b}{ 600a}{ 600d}{ (600f)} {-- 600x }{-- 600z }{-- 600y}<br />|\r\n#604||<a href="opac-search.pl?op=do_search&marclist=6049&operator==&type=intranet&value={6049}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6049}"></a>{ 604a}{. 604t}<br />|\r\n#601||<a href="opac-search.pl?op=do_search&marclist=6019&operator==&type=intranet&value={6019}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6019}"></a>{ 601a}{ (601c)}{. 601b}{ : 601d} { ; 601f}{ ; 601e}{ -- 601x }{-- 601z }{-- 601y}<br />|\r\n#605||<a href="opac-search.pl?op=do_search&marclist=6059&operator==&type=intranet&value={6059}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6059}"></a>{ 605a}{. 605i}{. 605h}{. 605k}{. 605m}{. 605q} {-- 605x }{-- 605z }{-- 605y }{-- 605l}<br />|\r\n#606||<a href="opac-search.pl?op=do_search&marclist=6069&operator==&type=intranet&value={6069}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6069}">xx</a>{ 606a}{-- 606x }{-- 606z }{606y }<br />|\r\n#607||<a href="opac-search.pl?op=do_search&marclist=6079&operator==&type=intranet&value={6079}"><img border="0" src="/opac-tmpl/css/en/images/filefind.png" height="15" title="Search on {6079}"></a>{ 607a}{-- 607x}{-- 607z}{-- 607y}<br />|\r\n#010|<label class="ipt">ISBN : </label>|{010a}|<br/>\r\n#011|<label class="ipt">ISSN : </label>|{011a}|<br/>\r\n#200||<label class="ipt">Notes : </label>|<br/>\r\n#300||{300a}|<br/>\r\n#320||{320a}|<br/>\r\n#327||{327a}|<br/>\r\n#328||{328a}|<br/>\r\n#200||<br/><h2>Exemplaires</h2>|\r\n#200|<table>|<th>Localisation</th><th>Cote</th>|\r\n#995||<tr><td>{995e}&nbsp;&nbsp;</td><td> {995k}</td></tr>|</table>', 'Ca paramètre permet de définir la grille ISBD', '90|20', 'Textarea');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IssueLog', '0', 'Activer ce paramètre pour enregistrer les actions sur la circulation','' , 'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IssuingInProcess', '0', 'N''affiche pas d''alerte si l''adhérent a des prêts qui accumulent des pénalités', '', 'YesNo');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itembarcodelength','','Number of characters in system-wide barcode schema (item barcodes).','','Integer');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itemcallnumber', '676a', 'Ce paramètre définit le champ/sous-champ que Koha va utiliser pour pré-remplir la cote des exemplaires. Par exemple, en cas de cote basée sur dewey, mettre 676a.', '', 'free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('DefaultClassificationSource','ddc','Default classification scheme used by the collection. E.g., Dewey, LCC, etc.', NULL,'ClassSources');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('KohaAdminEmailAddress', '', 'Ce paramètre contient l''adresse de l''administrateur du système', '', 'free');
@@ -97,6 +98,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserjs','','Define custom javascript for inclusion in OPAC','70|10','Textarea');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacTopissue', '1', 'Active ou non le palmarès des prêts à l''OPAC', '', 'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserlogin', '1', 'si ce paramètre est activé, les adhérents peuvent s''identifier à l''OPAC. Sinon seule la consultation anonyme est possible', '', 'YesNo');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).','','Integer');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronimages', 'jpg', 'Ce paramètre permet d''activer la gestion des photos des adhérents. Mettre une extension d''image (jpg) pour activer la chose', '', 'free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('printcirculationslips', '1', 'Active ou non l''impression de tickets de circulation', '', 'free');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReadingHistory', '0', 'Active ou non l''affichage de l''historique de lecture ', NULL, 'YesNo');
View
2  installer/data/mysql/kohastructure.sql
@@ -551,6 +551,8 @@ CREATE TABLE `branches` (
`issuing` tinyint(4) default NULL,
`branchip` varchar(15) default NULL,
`branchprinter` varchar(100) default NULL,
+ `itembarcodeprefix` varchar(10) default NULL,
+ `patronbarcodeprefix` varchar(10) default NULL,
UNIQUE KEY `branchcode` (`branchcode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
View
14 installer/data/mysql/updatedatabase.pl
@@ -3126,6 +3126,20 @@
print STDERR "Upgrade to $DBversion done ( Add xtags and xtags_and_saved_sql tables. )";
SetLibLimeVersion ($DBversion);
}
+
+$DBversion = '3.01.00.013';
+if (C4::Context->preference("LibLimeVersion") < TransformToNum($DBversion)) {
+ $dbh->do('ALTER TABLE branches ADD COLUMN itembarcodeprefix varchar(10) DEFAULT NULL' );
+ $dbh->do('ALTER TABLE branches ADD COLUMN patronbarcodeprefix varchar(10) DEFAULT NULL' );
+ $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,type)
+ VALUES ('itembarcodelength','','Number of characters in system-wide barcode schema (item barcodes).','Integer')");
+ $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,type)
+ VALUES ('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).','Integer')");
+ print "Upgrade to $DBversion done (Add barcode schema information for autobarcode and barcode input filters.)\n";
+ SetLibLimeVersion($DBversion);
+}
+
+
=item DropAllForeignKeys($table)
Drop all foreign keys of the table $table
View
17 koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tmpl
@@ -113,20 +113,9 @@
<li><label for="branchfax">Fax</label><input type="text" name="branchfax" id="branchfax" value="<!-- TMPL_VAR name="branchfax" escape="HTML" -->" /></li>
<li><label for="branchemail">Email</label><input type="text" name="branchemail" id="branchemail" value="<!-- TMPL_VAR name="branchemail" escape="HTML" -->" /></li>
<li><label for="branchip">IP</label><input type="text" name="branchip" id="branchip" value="<!-- TMPL_VAR name="branchip" escape="HTML" -->" /> <span class="hint">Can be entered as a single IP, or a subnet such as 192.168.1.*</span></li>
- <!--
- <li><label for="branchprinter">Library Printer</label>
- <select id="branchprinter" name="branchprinter">
- <option value="">None</option>
- <!-- TMPL_LOOP NAME="printerloop" -->
- <!-- TMPL_IF NAME="selected" -->
- <option value="<!-- TMPL_VAR NAME="value" -->" selected="selected"><!-- TMPL_VAR NAME="branchprinter" --></option>
- <!-- TMPL_ELSE -->
- <option value="<!-- TMPL_VAR NAME="value" -->"><!-- TMPL_VAR NAME="branchprinter" --></option>
- <!-- /TMPL_IF -->
- <!-- /TMPL_LOOP -->
- </select></li>
- -->
- </ol>
+ <!-- TMPL_IF NAME="itembarcodelength" --><li><label for="itembarcodeprefix">Item barcode prefix</label><input type="text" name="itembarcodeprefix" id="itembarcodeprefix" value="<!-- TMPL_VAR name="itembarcodeprefix" -->" /></li><!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="patronbarcodelength" --><li><label for="patronbarcodeprefix">Patron barcode prefix</label><input type="text" name="patronbarcodeprefix" id="patronbarcodeprefix" value="<!-- TMPL_VAR name="patronbarcodeprefix" -->" /></li><!-- /TMPL_IF -->
+ </ol>
</fieldset>
<fieldset class="action"><input type="submit" value="Submit" /> <a class="cancel" href="/cgi-bin/koha/admin/branches.pl">Cancel</a></fieldset>
</form>
View
51 koha-tmpl/intranet-tmpl/prog/en/modules/circ/hold-transfer-slip.tmpl
@@ -3,31 +3,36 @@
<!-- TMPL_INCLUDE NAME="doc-head-close-receipt.inc" -->
</head>
<body onload="window.print();">
-<div id="main">
+<div id="holdslip">
<!-- TMPL_LOOP NAME="reservedata" -->
<h5>Date: <!-- TMPL_VAR NAME="pulldate" --></h5>
-<h3> <!-- TMPL_IF NAME="transferrequired" -->Transfer to <!-- TMPL_VAR Name="branchname" --> <!-- TMPL_ELSE -->Hold in <!-- TMPL_VAR Name="branchname" --><!-- /TMPL_IF --></h3>
-
-<div id="reserve_display">
-
-<h3><!-- TMPL_VAR Name="surname" -->, <!-- TMPL_VAR Name="firstname" --></h3>
-
+<h3 class="transferdata"> <!-- TMPL_IF NAME="transferrequired" -->Transfer to <!-- TMPL_ELSE -->Hold in <!-- /TMPL_IF --> <!-- TMPL_VAR Name="pickup_library" --></h3>
+<div id="patrondata">
+<h3>For patron:</h3>
<ul>
- <li><!-- TMPL_VAR Name="cardnumber" --></li>
- <li><!-- TMPL_VAR Name="phone" --></li>
- <li><!-- TMPL_VAR Name="address" --><br />
- <!-- TMPL_IF Name="address2" --><!-- TMPL_VAR Name="address2" --><br /><!-- /TMPL_IF -->
- <!-- TMPL_VAR Name="city" --> <!-- TMPL_VAR NAME="zip" --></li>
- <!-- TMPL_IF NAME="email" --><li><!-- TMPL_VAR NAME="email" --></li> <!-- /TMPL_IF -->
-</ul>
-<br />
-<h3>RESERVED ITEM</h3>
- <h4><!-- TMPL_VAR Name="title" escape="html" --></h4>
- <h5><!-- TMPL_VAR NAME="author" --> </h5>
- <p><!-- TMPL_VAR Name="barcode" --></p>
-
-
-
- <!-- /TMPL_LOOP -->
+ <li class="patrondetails name"><!-- TMPL_VAR Name="surname" -->, <!-- TMPL_VAR Name="firstname" --></li>
+ <li><!-- TMPL_VAR Name="cardnumber" --></li>
+ <!-- TMPL_IF NAME="phone" --><li class="patrondetails phone"><!-- TMPL_VAR Name="phone" --></li><!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="address" --><li class="patrondetails address"><!-- TMPL_VAR Name="address" --><br />
+ <!-- TMPL_IF Name="address2" --><!-- TMPL_VAR Name="address2" --><br /><!-- /TMPL_IF -->
+ <!-- TMPL_VAR Name="city" --> <!-- TMPL_VAR NAME="zip" --></li><!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="email" --><li class="patrondetails email"><!-- TMPL_VAR NAME="email" --></li> <!-- /TMPL_IF -->
+ </ul>
+</div>
+<div id="itemdata">
+<h3>Held Item:</h3>
+ <h4 class="title"><!-- TMPL_VAR Name="title" escape="html" --></h4>
+ <h5 class="author"><!-- TMPL_VAR NAME="author" --> </h5>
+ <!-- TMPL_IF NAME="barcode-img" -->
+ <div id="barcode_img" class="itemdetails">
+ <img id="barcode_img" src="/cgi-bin/koha/circ/barcode-img.pl?barcode=<!-- TMPL_VAR NAME="barcode" -->" />
+ </div>
+ <!-- TMPL_ELSE -->
+ <p class="barcode"><!-- TMPL_VAR Name="barcode" --></p>
+<!-- /TMPL_IF -->
+<p class="home_library">Item owned by <!-- TMPL_VAR NAME="owning_library" --></p>
+</div>
+ <!-- /TMPL_LOOP -->
</div>
<!-- TMPL_INCLUDE NAME="intranet-bottom.inc" -->
+
View
8 members/memberentry.pl
@@ -380,8 +380,6 @@ BEGIN
$template->param( updtype => 'M',modify => 1 );
$template->param( step_1=>1, step_2=>1, step_3=>1, step_4=>1, step_5 => 1) unless $step;
}
-# my $cardnumber=$data{'cardnumber'};
-$data{'cardnumber'}=fixup_cardnumber($data{'cardnumber'}) if $op eq 'add';
if(!defined($data{'sex'})){
$template->param( none => 1);
} elsif($data{'sex'} eq 'F'){
@@ -519,6 +517,12 @@ BEGIN
$select_branches{$branch} = $branches->{$branch}->{'branchname'};
$default = C4::Context->userenv->{'branch'} if (C4::Context->userenv && C4::Context->userenv->{'branch'});
}
+# my $cardnumber=$data{'cardnumber'};
+# FIXME : Is there really a need to deliver an auto-calculated cardnumber to the entry form ?
+# We should just calculate it on submission, as that would allow the user to change branches without having to
+# recalculate (if a branch prefix is used), and would eliminate the race condition weakness here. The cardnumber
+# will be reported when the patron account is created. (but leaving as is for now).
+$data{'cardnumber'}=fixup_cardnumber($data{'cardnumber'}, $branches->{C4::Context->userenv->{'branch'}}) if $op eq 'add';
# --------------------------------------------------------------------------------------------------------
#in modify mod :default value from $CGIbranch comes from borrowers table
#in add mod: default value come from branches table (ip correspendence)
View
4 offline_circ/process_koc.pl
@@ -231,7 +231,7 @@ sub arguments_for_command {
sub kocIssueItem {
my $circ = shift;
- $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
+ $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && ( C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength')));
my $branchcode = C4::Context->userenv->{branch};
my $borrower = GetMember( $circ->{ 'cardnumber' }, 'cardnumber' );
my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
@@ -324,7 +324,7 @@ sub kocIssueItem {
sub kocReturnItem {
my ( $circ ) = @_;
- $circ->{'barcode'} = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
+ $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && ( C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength')));
my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
#warn( Data::Dumper->Dump( [ $circ, $item ], [ qw( circ item ) ] ) );
my $borrowernumber = _get_borrowernumber_from_barcode( $circ->{'barcode'} );
View
7 tools/import_borrowers.pl
@@ -40,7 +40,7 @@
use C4::Output;
use C4::Dates qw(format_date_in_iso);
use C4::Context;
-use C4::Branch qw(GetBranchName);
+use C4::Branch qw(GetBranchName GetBranches);
use C4::Members;
use C4::Members::Attributes qw(:all);
use C4::Members::AttributeTypes;
@@ -98,6 +98,9 @@
($extended) and $template->param(ExtendedPatronAttributes => 1);
+# FIXME : this tool will currently allow patrons to be imported to any library, uncontrolled by Independent branches.
+my $branches=GetBranches();
+
if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
push @feedback, {feedback=>1, name=>'filename', value=>$uploadborrowers, filename=>$uploadborrowers};
my $handle = $input->upload('uploadborrowers');
@@ -264,7 +267,7 @@
# FIXME: fixup_cardnumber says to lock table, but the web interface doesn't so this doesn't either.
# At least this is closer to AddMember than in members/memberentry.pl
if (!$borrower{'cardnumber'}) {
- $borrower{'cardnumber'} = fixup_cardnumber(undef);
+ $borrower{'cardnumber'} = fixup_cardnumber(undef,$branches->{$borrower{'branchcode'}});
}
if ($borrowernumber = AddMember(%borrower)) {
if ($extended) {
Please sign in to comment.
Something went wrong with that request. Please try again.