View | Details | Raw Unified | Return to bug 7676
Collapse All | Expand All

(-)a/C4/Barcodes.pm (+2 lines)
Lines 28-33 use C4::Dates; Link Here
28
use C4::Barcodes::hbyymmincr;
28
use C4::Barcodes::hbyymmincr;
29
use C4::Barcodes::annual;
29
use C4::Barcodes::annual;
30
use C4::Barcodes::incremental;
30
use C4::Barcodes::incremental;
31
use C4::Barcodes::prefix;
31
32
32
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
33
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
33
use vars qw($debug $cgi_debug);	# from C4::Debug, of course
34
use vars qw($debug $cgi_debug);	# from C4::Debug, of course
Lines 173-178 sub default_self (;$) { Link Here
173
}
174
}
174
175
175
our $types = {
176
our $types = {
177
        prefix_incr => sub {C4::Barcodes::prefix->new_object(@_);     },
176
	annual      => sub {C4::Barcodes::annual->new_object(@_);     },
178
	annual      => sub {C4::Barcodes::annual->new_object(@_);     },
177
	incremental => sub {C4::Barcodes::incremental->new_object(@_);},
179
	incremental => sub {C4::Barcodes::incremental->new_object(@_);},
178
	hbyymmincr  => sub {C4::Barcodes::hbyymmincr->new_object(@_); },
180
	hbyymmincr  => sub {C4::Barcodes::hbyymmincr->new_object(@_); },
(-)a/C4/Barcodes/prefix.pm (+126 lines)
Line 0 Link Here
1
package C4::Barcodes::prefix;
2
3
# Copyright 2011 ByWater Solutions
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use Carp;
23
24
use C4::Context;
25
use C4::Branch;
26
use C4::Debug;
27
use C4::Dates;
28
29
use vars qw($VERSION @ISA);
30
use vars qw($debug $cgi_debug);        # from C4::Debug, of course
31
use vars qw($branch $width);
32
33
BEGIN {
34
    $VERSION = 0.01;
35
    @ISA = qw(C4::Barcodes);
36
    $width = C4::Context->preference('itembarcodelength');
37
    my $prefix = '';
38
}
39
40
41
# This package generates auto-incrementing barcodes where branch-specific prefixes are being used.
42
# For a library with 10-digit barcodes, and a prefix of T123, this should generate on a range of
43
# T123000000 and T123999999
44
#
45
# There are a couple of problems with treating barcodes as straight-numerics and just incrementing
46
# them.  The first, and most-obvious, is that barcodes need not be numeric, particularly in the prefix
47
# part!  The second, as noted in C4::Barcodes.pm, is that you might not actually be able to handle very
48
# large ints like that...
49
50
51
sub db_max ($;$) {
52
        my $self = shift;
53
        my $sth = C4::Context->dbh->prepare("SELECT MAX(barcode) AS biggest FROM items where barcode LIKE ? AND length(barcode) =?");
54
        my $prefix_search = $self->prefix . '%';
55
        $sth->execute($prefix_search, $self->width);
56
        return $self->initial unless ($sth->rows);
57
        my ($row) = $sth->fetchrow_hashref();
58
59
        my $max = $row->{biggest};
60
        return ($max || 0);
61
}
62
63
sub initial () {
64
        my $self = shift;
65
        my $increment_width = $self->width - length($self->prefix);
66
        return $self->prefix . sprintf("%"."$increment_width.$increment_width"."d",1);
67
}
68
69
sub parse ($;$) {   # return 3 parts of barcode: non-incrementing, incrementing, non-incrementing
70
        my $self = shift;
71
        my $barcode = (@_) ? shift : $self->value;
72
        my $prefix = $self->prefix;
73
        unless ($barcode =~ /($prefix)(.+)$/) {
74
           return($barcode,undef,undef);
75
        }
76
        return ($1,$2,'');  # the third part is in anticipation of barcodes that include checkdigits
77
}
78
79
sub prefix ($;$) {
80
        my $self = shift;
81
        (@_) and $self->{prefix} = shift;
82
        return C4::Branch::GetBranchDetail(C4::Context->userenv->{'branch'})->{'itembarcodeprefix'};
83
}
84
85
sub width ($;$) {
86
       my $self = shift;
87
       (@_) and $width = shift;        # hitting the class variable.
88
       return $width;
89
}
90
91
sub next_value ($;$) {
92
    my $self = shift;
93
    my $specific = (scalar @_) ? 1 : 0;
94
    my $max = $specific ? shift : $self->max;
95
    return $self->initial unless ($max);
96
    my ($head,$incr,$tail) = $self->parse($max);
97
    return undef unless (defined $incr);
98
    my $incremented = '';
99
100
    while ($incr =~ /([a-zA-Z]*[0-9]*)\z/ ){
101
       my $fragment = $1;
102
       $fragment++;   #yes, you can do that with strings.  Clever.
103
       if (length($fragment) > length($1)){   #uhoh.  got to carry something over.
104
          $incremented = substr($fragment,1) . $incremented;
105
          $incr = $`;    #prematch.  grab everything *before* $1 from above, and go back thru this.
106
       }
107
       else {   #we're okay now.
108
          $incr = $` . $fragment . $incremented;
109
          last;
110
       }
111
    }
112
113
    my $next_val = $head . $incr .$tail;
114
    return $next_val;
115
}
116
117
sub new_object {
118
        my $class_or_object = shift;
119
        my $type = ref($class_or_object) || $class_or_object;
120
        my $self = $type->default_self('prefix_incr');
121
        # take the prefix from argument, or the existing object, or get it from the userenv, in that order
122
        return bless $self, $type;
123
}
124
125
1;
126
__END__
(-)a/C4/Circulation.pm (+5 lines)
Lines 169-174 sub barcodedecode { Link Here
169
			}
169
			}
170
		}
170
		}
171
	}
171
	}
172
        if(C4::Context->preference('itembarcodelength') && (length($barcode) < C4::Context->preference('itembarcodelength'))) {
173
                my $prefix = GetBranchDetail(C4::Context->userenv->{'branch'})->{'itembarcodeprefix'} ;
174
                my $padding = C4::Context->preference('itembarcodelength') - length($prefix) - length($barcode) ;
175
                $barcode = $prefix . '0' x $padding . $barcode if($padding >= 0) ;
176
        }
172
    return $barcode;    # return barcode, modified or not
177
    return $barcode;    # return barcode, modified or not
173
}
178
}
174
179
(-)a/C4/ILSDI/Services.pm (-1 / +2 lines)
Lines 509-515 sub GetServices { Link Here
509
509
510
    # Issuing management
510
    # Issuing management
511
    my $barcode = $item->{'barcode'} || '';
511
    my $barcode = $item->{'barcode'} || '';
512
    $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') );
512
    $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') 
513
                                            || C4::Context->preference('itembarcodelength') );
513
    if ($barcode) {
514
    if ($barcode) {
514
        my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
515
        my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
515
516
(-)a/C4/Items.pm (+29 lines)
Lines 256-261 sub AddItem { Link Here
256
    $sth->execute( $item->{'biblionumber'} );
256
    $sth->execute( $item->{'biblionumber'} );
257
    ($item->{'biblioitemnumber'}) = $sth->fetchrow;
257
    ($item->{'biblioitemnumber'}) = $sth->fetchrow;
258
258
259
    _check_itembarcode($item) if (C4::Context->preference('itembarcodelength'));
259
    _set_defaults_for_add($item);
260
    _set_defaults_for_add($item);
260
    _set_derived_columns_for_add($item);
261
    _set_derived_columns_for_add($item);
261
    $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
262
    $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
Lines 356-361 sub AddItemBatchFromMarc { Link Here
356
            next ITEMFIELD;
357
            next ITEMFIELD;
357
        }
358
        }
358
359
360
        _check_itembarcode($item) if (C4::Context->preference('itembarcodelength'));
359
        _set_defaults_for_add($item);
361
        _set_defaults_for_add($item);
360
        _set_derived_columns_for_add($item);
362
        _set_derived_columns_for_add($item);
361
        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
363
        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
Lines 2493-2498 sub GetItemHolds { Link Here
2493
    $holds = $sth->fetchrow;
2495
    $holds = $sth->fetchrow;
2494
    return $holds;
2496
    return $holds;
2495
}
2497
}
2498
2496
=head1  OTHER FUNCTIONS
2499
=head1  OTHER FUNCTIONS
2497
2500
2498
=head2 _find_value
2501
=head2 _find_value
Lines 2758-2761 sub PrepareItemrecordDisplay { Link Here
2758
    };
2761
    };
2759
}
2762
}
2760
2763
2764
=head2 _check_itembarcode
2765
2766
=over 4
2767
2768
&_check_itembarcode
2769
2770
=back
2771
2772
Modifies item barcode value to include prefix defined in branches.itembarcodeprefix
2773
if the length is less than the syspref itembarcodelength .
2774
2775
=cut
2776
sub _check_itembarcode($) {
2777
    my $item = shift;
2778
    return(0) unless $item->{'barcode'}; # only modify if we've been passed a barcode.
2779
    # check item barcode prefix
2780
    # note this doesn't enforce barcodelength.
2781
    my $branch_prefix = GetBranchDetail($item->{'homebranch'})->{'itembarcodeprefix'};
2782
    if(length($item->{'barcode'}) < C4::Context->preference('itembarcodelength')) {
2783
        my $padding = C4::Context->preference('itembarcodelength') - length($branch_prefix) - length($item->{'barcode'}) ;
2784
        $item->{'barcode'} = $branch_prefix .  '0' x $padding . $item->{'barcode'} if($padding >= 0) ;
2785
    } else {
2786
      #  $errors{'invalid_barcode'} = $item->{'barcode'};
2787
    }
2788
}
2789
2761
1;
2790
1;
(-)a/C4/Members.pm (-14 / +82 lines)
Lines 38-43 use C4::NewsChannels; #get slip news Link Here
38
use DateTime;
38
use DateTime;
39
use DateTime::Format::DateParse;
39
use DateTime::Format::DateParse;
40
use Koha::DateUtils;
40
use Koha::DateUtils;
41
use C4::Branch qw(GetBranchDetail);
41
42
42
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
43
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
43
44
Lines 176-185 sub _express_member_find { Link Here
176
    # so we can check an exact match first, if that works return, otherwise do the rest
177
    # so we can check an exact match first, if that works return, otherwise do the rest
177
    my $dbh   = C4::Context->dbh;
178
    my $dbh   = C4::Context->dbh;
178
    my $query = "SELECT borrowernumber FROM borrowers WHERE cardnumber = ?";
179
    my $query = "SELECT borrowernumber FROM borrowers WHERE cardnumber = ?";
179
    if ( my $borrowernumber = $dbh->selectrow_array($query, undef, $filter) ) {
180
    my $cardnum = _prefix_cardnum($filter);
181
    if ( my $borrowernumber = $dbh->selectrow_array($query, undef, $cardnum) ) {
180
        return( {"borrowernumber"=>$borrowernumber} );
182
        return( {"borrowernumber"=>$borrowernumber} );
181
    }
183
    }
182
183
    my ($search_on_fields, $searchtype);
184
    my ($search_on_fields, $searchtype);
184
    if ( length($filter) == 1 ) {
185
    if ( length($filter) == 1 ) {
185
        $search_on_fields = [ qw(surname) ];
186
        $search_on_fields = [ qw(surname) ];
Lines 718-723 sub ModMember { Link Here
718
            $data{password} = md5_base64($data{password});
719
            $data{password} = md5_base64($data{password});
719
        }
720
        }
720
    }
721
    }
722
723
    # modify cardnumber with prefix, if needed.
724
    if(C4::Context->preference('patronbarcodelength') && exists($data{'cardnumber'})){
725
        $data{'cardnumber'} = _prefix_cardnum($data{'cardnumber'});
726
    }
727
721
	my $execute_success=UpdateInTable("borrowers",\%data);
728
	my $execute_success=UpdateInTable("borrowers",\%data);
722
    if ($execute_success) { # only proceed if the update was a success
729
    if ($execute_success) { # only proceed if the update was a success
723
        # ok if its an adult (type) it may have borrowers that depend on it as a guarantor
730
        # ok if its an adult (type) it may have borrowers that depend on it as a guarantor
Lines 753-758 sub AddMember { Link Here
753
	$data{'userid'} = Generate_Userid($data{'borrowernumber'}, $data{'firstname'}, $data{'surname'}) if $data{'userid'} eq '';
760
	$data{'userid'} = Generate_Userid($data{'borrowernumber'}, $data{'firstname'}, $data{'surname'}) if $data{'userid'} eq '';
754
	# create a disabled account if no password provided
761
	# create a disabled account if no password provided
755
	$data{'password'} = ($data{'password'})? md5_base64($data{'password'}) : '!';
762
	$data{'password'} = ($data{'password'})? md5_base64($data{'password'}) : '!';
763
        $data{'cardnumber'} = _prefix_cardnum($data{'cardnumber'}) if(C4::Context->preference('patronbarcodelength'));
764
756
	$data{'borrowernumber'}=InsertInTable("borrowers",\%data);	
765
	$data{'borrowernumber'}=InsertInTable("borrowers",\%data);	
757
    # mysql_insertid is probably bad.  not necessarily accurate and mysql-specific at best.
766
    # mysql_insertid is probably bad.  not necessarily accurate and mysql-specific at best.
758
    logaction("MEMBERS", "CREATE", $data{'borrowernumber'}, "") if C4::Context->preference("BorrowersLog");
767
    logaction("MEMBERS", "CREATE", $data{'borrowernumber'}, "") if C4::Context->preference("BorrowersLog");
Lines 846-853 mode, to avoid database corruption. Link Here
846
use vars qw( @weightings );
855
use vars qw( @weightings );
847
my @weightings = ( 8, 4, 6, 3, 5, 2, 1 );
856
my @weightings = ( 8, 4, 6, 3, 5, 2, 1 );
848
857
849
sub fixup_cardnumber ($) {
858
sub fixup_cardnumber {
850
    my ($cardnumber) = @_;
859
    my ($cardnumber,$branch) = @_;
851
    my $autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0;
860
    my $autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0;
852
861
853
    # Find out whether member numbers should be generated
862
    # Find out whether member numbers should be generated
Lines 895-911 sub fixup_cardnumber ($) { Link Here
895
904
896
        return "V$cardnumber$rem";
905
        return "V$cardnumber$rem";
897
     } else {
906
     } else {
907
        my $cardlength = C4::Context->preference('patronbarcodelength');
908
        if (defined($cardnumber) && (length($cardnumber) == $cardlength) && $cardnumber =~ m/^$branch->{'patronbarcodeprefix'}/ ) {
909
           return $cardnumber;
910
        }
898
911
899
     # MODIFIED BY JF: mysql4.1 allows casting as an integer, which is probably
912
     # increment operator without cast(int) should be safe, and should properly increment
900
     # better. I'll leave the original in in case it needs to be changed for you
913
     # whether the string is numeric or not.
901
     # my $sth=$dbh->prepare("select max(borrowers.cardnumber) from borrowers");
914
     # FIXME : This needs to be pulled out into an ajax function, since the interface allows on-the-fly changing of patron home library.
902
        my $sth = $dbh->prepare(
915
     #
903
            "select max(cast(cardnumber as signed)) from borrowers"
916
         my $query =  "select max(borrowers.cardnumber) from borrowers ";
904
        );
917
         my @bind;
905
        $sth->execute;
918
         my $firstnumber = 0;
906
        my ($result) = $sth->fetchrow;
919
         if($branch->{'patronbarcodeprefix'} && $cardlength) {
907
        return $result + 1;
920
             my $cardnum_search = $branch->{'patronbarcodeprefix'} . '%';
908
    }
921
             $query .= " WHERE cardnumber LIKE ?";
922
             $query .= " AND length(cardnumber) = ?";
923
             @bind = ($cardnum_search,$cardlength ) ;
924
         }
925
         my $sth= $dbh->prepare($query);
926
         $sth->execute(@bind);
927
         my ($result) = $sth->fetchrow;
928
         $sth->finish;
929
         if($result) {
930
             my $cnt = 0;
931
             $result =~ s/^$branch->{'patronbarcodeprefix'}//;
932
             while ( $result =~ /([a-zA-Z]*[0-9]*)\z/ ) {   # use perl's magical stringcrement behavior (++).
933
                 my $incrementable = $1;
934
                 $incrementable++;
935
                 if ( length($incrementable) > length($1) ) { # carry a digit to next incrementable fragment
936
                     $cardnumber = substr($incrementable,1) . $cardnumber;
937
                     $result = $`;
938
                 } else {
939
                     $cardnumber = $branch->{'patronbarcodeprefix'} . $` . $incrementable . $cardnumber ;
940
                     last;
941
                 }
942
                 last if(++$cnt>10);
943
             }
944
         } else {
945
             $cardnumber =  ++$firstnumber ;
946
         }
947
     }
909
    return $cardnumber;     # just here as a fallback/reminder 
948
    return $cardnumber;     # just here as a fallback/reminder 
910
}
949
}
911
950
Lines 2345-2350 sub GetBorrowersWithEmail { Link Here
2345
    return @result;
2384
    return @result;
2346
}
2385
}
2347
2386
2387
=head2 _prefix_cardnum
2388
2389
=over 4
2390
2391
$cardnum = _prefix_cardnum($cardnum,$branchcode);
2392
2393
If a system-wide barcode length is defined, and a prefix defined for the passed branch or the user's branch,
2394
modify the barcode by prefixing and padding.
2395
2396
=back
2397
=cut
2398
2399
sub _prefix_cardnum{
2400
    my ($cardnum,$branchcode) = @_;
2401
2402
    if(C4::Context->preference('patronbarcodelength') && (length($cardnum) < C4::Context->preference('patronbarcodelength'))) {
2403
        #if we have a system-wide cardnum length and a branch prefix, prepend the prefix.
2404
        if( ! $branchcode && defined(C4::Context->userenv) ) {
2405
            $branchcode = C4::Context->userenv->{'branch'};
2406
        }
2407
        return $cardnum unless $branchcode;
2408
        my $branch = GetBranchDetail( $branchcode );
2409
        return $cardnum unless( defined($branch) && defined($branch->{'patronbarcodeprefix'}) );
2410
        my $prefix = $branch->{'patronbarcodeprefix'} ;
2411
        my $padding = C4::Context->preference('patronbarcodelength') - length($prefix) - length($cardnum) ;
2412
        $cardnum = $prefix . '0' x $padding . $cardnum if($padding >= 0) ;
2413
   }
2414
    return $cardnum;
2415
}
2348
2416
2349
END { }    # module clean-up code here (global destructor)
2417
END { }    # module clean-up code here (global destructor)
2350
2418
(-)a/admin/branches.pl (-2 / +6 lines)
Lines 68-75 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
68
    }
68
    }
69
);
69
);
70
$template->param(
70
$template->param(
71
     script_name => $script_name,
71
     script_name         => $script_name,
72
     action      => $script_name,
72
     action              => $script_name,
73
     itembarcodelength   => C4::Context->preference('itembarcodelength'),
74
     patronbarcodelength => C4::Context->preference('patronbarcodelength'),
73
);
75
);
74
$template->param( ($op || 'else') => 1 );
76
$template->param( ($op || 'else') => 1 );
75
77
Lines 410-415 sub _branch_to_template { Link Here
410
         opac_info      => $data->{'opac_info'},
412
         opac_info      => $data->{'opac_info'},
411
         branchip       => $data->{'branchip'},
413
         branchip       => $data->{'branchip'},
412
         branchnotes    => $data->{'branchnotes'}, 
414
         branchnotes    => $data->{'branchnotes'}, 
415
         itembarcodeprefix    => $data->{'itembarcodeprefix'},
416
         patronbarcodeprefix  => $data->{'patronbarcodeprefix'},
413
    );
417
    );
414
}
418
}
415
419
(-)a/admin/systempreferences.pl (+2 lines)
Lines 124-129 $tabsysprefs{soundon} = "Admin"; Link Here
124
$tabsysprefs{SpineLabelShowPrintOnBibDetails}   = "Admin";
124
$tabsysprefs{SpineLabelShowPrintOnBibDetails}   = "Admin";
125
$tabsysprefs{WebBasedSelfCheckHeader}           = "Admin";
125
$tabsysprefs{WebBasedSelfCheckHeader}           = "Admin";
126
$tabsysprefs{WebBasedSelfCheckTimeout}          = "Admin";
126
$tabsysprefs{WebBasedSelfCheckTimeout}          = "Admin";
127
$tabsysprefs{itembarcodelength}     = "Admin";
128
$tabsysprefs{patronbarcodelength}   = "Admin";
127
129
128
# Authorities
130
# Authorities
129
$tabsysprefs{authoritysep}          = "Authorities";
131
$tabsysprefs{authoritysep}          = "Authorities";
(-)a/cataloguing/additem.pl (+8 lines)
Lines 347-352 if ($op eq "additem") { Link Here
347
	push @errors,"barcode_not_unique" if($exist_itemnumber);
347
	push @errors,"barcode_not_unique" if($exist_itemnumber);
348
	# if barcode exists, don't create, but report The problem.
348
	# if barcode exists, don't create, but report The problem.
349
    unless ($exist_itemnumber) {
349
    unless ($exist_itemnumber) {
350
            unless ($addedolditem->{'barcode'}) {
351
               use C4::Barcodes;
352
               my $barcodeobj = C4::Barcodes->new();
353
               my $db_max = $barcodeobj->db_max();
354
               my $nextbarcode = $barcodeobj->next_value($db_max);
355
               my ($tagfield,$tagsubfield) = &GetMarcFromKohaField("items.barcode",$frameworkcode);
356
               $record->field($tagfield)->update($tagsubfield => "$nextbarcode") if ($nextbarcode);
357
            }
350
	    my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = AddItemFromMarc($record,$biblionumber);
358
	    my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = AddItemFromMarc($record,$biblionumber);
351
        set_item_default_location($oldbibitemnum);
359
        set_item_default_location($oldbibitemnum);
352
    }
360
    }
(-)a/circ/circulation.pl (-1 / +2 lines)
Lines 120-126 if (C4::Context->preference("UseTablesortForCirc")) { Link Here
120
my $barcode        = $query->param('barcode') || '';
120
my $barcode        = $query->param('barcode') || '';
121
$barcode =~  s/^\s*|\s*$//g; # remove leading/trailing whitespace
121
$barcode =~  s/^\s*|\s*$//g; # remove leading/trailing whitespace
122
122
123
$barcode = barcodedecode($barcode) if( $barcode && C4::Context->preference('itemBarcodeInputFilter'));
123
$barcode = barcodedecode($barcode) if( $barcode && (C4::Context->preference('itemBarcodeInputFilter')
124
                                      ||  C4::Context->preference('itembarcodelength')));
124
my $stickyduedate  = $query->param('stickyduedate') || $session->param('stickyduedate');
125
my $stickyduedate  = $query->param('stickyduedate') || $session->param('stickyduedate');
125
my $duedatespec    = $query->param('duedatespec')   || $session->param('stickyduedate');
126
my $duedatespec    = $query->param('duedatespec')   || $session->param('stickyduedate');
126
my $issueconfirmed = $query->param('issueconfirmed');
127
my $issueconfirmed = $query->param('issueconfirmed');
(-)a/circ/returns.pl (-2 / +4 lines)
Lines 108-114 foreach ( $query->param ) { Link Here
108
108
109
    # decode barcode    ## Didn't we already decode them before passing them back last time??
109
    # decode barcode    ## Didn't we already decode them before passing them back last time??
110
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
110
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
111
    $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter'));
111
    $barcode = barcodedecode($barcode) if(C4::Context->preference('itemBarcodeInputFilter') 
112
                                          || C4::Context->preference('itembarcodelength'));
112
113
113
    ######################
114
    ######################
114
    #Are these lines still useful ?
115
    #Are these lines still useful ?
Lines 201-207 if ($canceltransfer){ Link Here
201
# actually return book and prepare item table.....
202
# actually return book and prepare item table.....
202
if ($barcode) {
203
if ($barcode) {
203
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
204
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
204
    $barcode = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter');
205
    $barcode = barcodedecode($barcode) if (C4::Context->preference('itemBarcodeInputFilter')
206
                                           || C4::Context->preference('itembarcodelength'));
205
    $itemnumber = GetItemnumberFromBarcode($barcode);
207
    $itemnumber = GetItemnumberFromBarcode($barcode);
206
208
207
    if ( C4::Context->preference("InProcessingToShelvingCart") ) {
209
    if ( C4::Context->preference("InProcessingToShelvingCart") ) {
(-)a/installer/data/mysql/kohastructure.sql (+2 lines)
Lines 365-370 CREATE TABLE `branches` ( -- information about your libraries or branches are st Link Here
365
  `branchprinter` varchar(100) default NULL, -- unused in Koha
365
  `branchprinter` varchar(100) default NULL, -- unused in Koha
366
  `branchnotes` mediumtext, -- notes related to your library or branch
366
  `branchnotes` mediumtext, -- notes related to your library or branch
367
  opac_info text, -- HTML that displays in OPAC
367
  opac_info text, -- HTML that displays in OPAC
368
  itembarcodeprefix varchar(10) default NULL, -- branch's item barcode prefix
369
  patronbarcodeprefix varchar(10) default NULL, -- branch's patron barcode prefix
368
  UNIQUE KEY `branchcode` (`branchcode`)
370
  UNIQUE KEY `branchcode` (`branchcode`)
369
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
371
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
370
372
(-)a/installer/data/mysql/sysprefs.sql (+2 lines)
Lines 53-58 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
53
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');
53
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');
54
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('item-level_itypes',1,'If ON, enables Item-level Itemtype / Issuing Rules','','YesNo');
54
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('item-level_itypes',1,'If ON, enables Item-level Itemtype / Issuing Rules','','YesNo');
55
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');
55
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');
56
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itembarcodelength','','Number of characters in system-wide barcode schema (item barcodes).','','Integer');
56
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');
57
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');
57
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('KohaAdminEmailAddress','root@localhost','Define the email address where patron modification requests are sent','','free');
58
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('KohaAdminEmailAddress','root@localhost','Define the email address where patron modification requests are sent','','free');
58
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('LabelMARCView','standard','Define how a MARC record will display','standard|economical','Choice');
59
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('LabelMARCView','standard','Define how a MARC record will display','standard|economical','Choice');
Lines 95-100 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
95
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacPublic',1,'Turn on/off public OPAC',NULL,'YesNo');
96
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacPublic',1,'Turn on/off public OPAC',NULL,'YesNo');
96
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserjs','','Define custom javascript for inclusion in OPAC','70|10','Textarea');
97
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserjs','','Define custom javascript for inclusion in OPAC','70|10','Textarea');
97
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserlogin',1,'Enable or disable display of user login features',NULL,'YesNo');
98
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserlogin',1,'Enable or disable display of user login features',NULL,'YesNo');
99
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).','','Integer');
98
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronimages',0,'Enable patron images for the Staff Client',NULL,'YesNo');
100
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronimages',0,'Enable patron images for the Staff Client',NULL,'YesNo');
99
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACpatronimages',0,'Enable patron images in the OPAC',NULL,'YesNo');
101
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACpatronimages',0,'Enable patron images in the OPAC',NULL,'YesNo');
100
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('printcirculationslips',1,'If ON, enable printing circulation receipts','','YesNo');
102
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('printcirculationslips',1,'If ON, enable printing circulation receipts','','YesNo');
(-)a/installer/data/mysql/updatedatabase.pl (+11 lines)
Lines 5095-5100 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
5095
    SetVersion($DBversion);
5095
    SetVersion($DBversion);
5096
}
5096
}
5097
5097
5098
5099
$DBversion = "3.07.00.XXX";
5100
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
5101
    $dbh->do("ALTER TABLE `branches` ADD `itembarcodeprefix` VARCHAR( 10 ) NULL AFTER `branchnotes`");
5102
    $dbh->do("ALTER TABLE `branches` ADD `patronbarcodeprefix` VARCHAR( 10 ) NULL AFTER `itembarcodeprefix`");
5103
    $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('itembarcodelength','','Number of characters in system-wide barcode schema (item barcodes).','','Integer')");
5104
    $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronbarcodelength','','Number of characters in system-wide barcode schema (patron cardnumbers).','','Integer')");
5105
    print "Upgrade to $DBversion done (Add barcode prefix feature. Add fields itembarcodeprefix and patronbarcodeprefix to table branches, add sysprefs itembarcodelength and patronbarcodelength)\n";
5106
    SetVersion($DBversion);
5107
}
5108
5098
=head1 FUNCTIONS
5109
=head1 FUNCTIONS
5099
5110
5100
=head2 DropAllForeignKeys($table)
5111
=head2 DropAllForeignKeys($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt (+6 lines)
Lines 143-148 tinyMCE.init({ Link Here
143
        <li><label for="branchurl">url</label><input type="text" name="branchurl" id="branchurl" value="[% branchurl |html %]" /></li>
143
        <li><label for="branchurl">url</label><input type="text" name="branchurl" id="branchurl" value="[% branchurl |html %]" /></li>
144
        <li><label for="opac_info">OPAC Info</label><textarea name="opac_info" id="opac_info">[% opac_info |html %]</textarea></li>
144
        <li><label for="opac_info">OPAC Info</label><textarea name="opac_info" id="opac_info">[% opac_info |html %]</textarea></li>
145
        <li><label for="branchip">IP</label><input type="text" name="branchip" id="branchip" value="[% branchip |html %]" /> <span class="hint">Can be entered as a single IP, or a subnet such as 192.168.1.*</span></li>
145
        <li><label for="branchip">IP</label><input type="text" name="branchip" id="branchip" value="[% branchip |html %]" /> <span class="hint">Can be entered as a single IP, or a subnet such as 192.168.1.*</span></li>
146
        [% IF ( itembarcodelength ) %]
147
           <li><label for="itembarcodeprefix">Item Barcode Prefix</label><input type="text" name="itembarcodeprefix" id="itembarcodeprefix" value="[% itembarcodeprefix |html %]" /></li>
148
        [% END %]
149
        [% IF ( patronbarcodelength ) %]
150
           <li><label for="patronbarcodeprefix">Patron Barcode Prefix</label><input type="text" name="patronbarcodeprefix" id="patronbarcodeprefix" value="[% patronbarcodeprefix |html %]" /></li>
151
        [% END %]
146
		<!--
152
		<!--
147
        <li><label for="branchprinter">Library Printer</label>
153
        <li><label for="branchprinter">Library Printer</label>
148
            <select id="branchprinter" name="branchprinter">
154
            <select id="branchprinter" name="branchprinter">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref (+10 lines)
Lines 40-45 Administration: Link Here
40
                  yes: Allow
40
                  yes: Allow
41
                  no: "Don't allow"
41
                  no: "Don't allow"
42
            - staff and patrons to create and view saved lists of books.
42
            - staff and patrons to create and view saved lists of books.
43
        -   
44
            - Use branch prefixes to ensure that item barcodes are
45
            - pref: itembarcodelength
46
              class: integer
47
            - digits long 
48
        -   
49
            - Use branch prefixes to ensure that patron barcodes are
50
            - pref: patronbarcodelength
51
              class: integer
52
            - digits long 
43
    Login options:
53
    Login options:
44
        -
54
        -
45
            - pref: insecure
55
            - pref: insecure
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref (+1 lines)
Lines 86-91 Cataloging: Link Here
86
            - Barcodes are
86
            - Barcodes are
87
            - pref: autoBarcode
87
            - pref: autoBarcode
88
              choices:
88
              choices:
89
                  prefix_incr: generated with the branch prefix, followed by a zero-padded form of 1, 2, 3.
89
                  incremental: generated in the form 1, 2, 3.
90
                  incremental: generated in the form 1, 2, 3.
90
                  annual: generated in the form &lt;year&gt;-0001, &lt;year&gt;-0002.
91
                  annual: generated in the form &lt;year&gt;-0001, &lt;year&gt;-0002.
91
                  hbyymmincr: generated in the form &lt;branchcode&gt;yymm0001.
92
                  hbyymmincr: generated in the form &lt;branchcode&gt;yymm0001.
(-)a/members/memberentry.pl (-7 / +8 lines)
Lines 433-439 if ( $op eq "duplicate" ) { Link Here
433
    $template->param( step_1 => 1, step_2 => 1, step_3 => 1, step_4 => 1, step_5 => 1, step_6 => 1 ) unless $step;
433
    $template->param( step_1 => 1, step_2 => 1, step_3 => 1, step_4 => 1, step_5 => 1, step_6 => 1 ) unless $step;
434
}
434
}
435
435
436
$data{'cardnumber'}=fixup_cardnumber($data{'cardnumber'}) if $op eq 'add';
436
my $onlymine=(C4::Context->preference('IndependantBranches') && 
437
              C4::Context->userenv && 
438
              C4::Context->userenv->{flags} % 2 !=1  && 
439
              C4::Context->userenv->{branch}?1:0);
440
              
441
my $branches=GetBranches($onlymine);
442
$data{'cardnumber'}=fixup_cardnumber( $data{'cardnumber'}, $branches->{C4::Context->userenv->{'branch'}} ) if $op eq 'add';
443
437
if(!defined($data{'sex'})){
444
if(!defined($data{'sex'})){
438
    $template->param( none => 1);
445
    $template->param( none => 1);
439
} elsif($data{'sex'} eq 'F'){
446
} elsif($data{'sex'} eq 'F'){
Lines 570-581 my @branches; Link Here
570
my @select_branch;
577
my @select_branch;
571
my %select_branches;
578
my %select_branches;
572
579
573
my $onlymine=(C4::Context->preference('IndependantBranches') && 
574
              C4::Context->userenv && 
575
              C4::Context->userenv->{flags} % 2 !=1  && 
576
              C4::Context->userenv->{branch}?1:0);
577
              
578
my $branches=GetBranches($onlymine);
579
my $default;
580
my $default;
580
my $CGIbranch;
581
my $CGIbranch;
581
for my $branch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
582
for my $branch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
(-)a/offline_circ/process_koc.pl (-2 / +2 lines)
Lines 241-247 sub arguments_for_command { Link Here
241
sub kocIssueItem {
241
sub kocIssueItem {
242
    my $circ = shift;
242
    my $circ = shift;
243
243
244
    $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
244
    $circ->{ 'barcode' } = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && (C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength')));
245
    my $branchcode = C4::Context->userenv->{branch};
245
    my $branchcode = C4::Context->userenv->{branch};
246
    my $borrower = GetMember( 'cardnumber'=>$circ->{ 'cardnumber' } );
246
    my $borrower = GetMember( 'cardnumber'=>$circ->{ 'cardnumber' } );
247
    my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
247
    my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
Lines 319-325 sub kocIssueItem { Link Here
319
319
320
sub kocReturnItem {
320
sub kocReturnItem {
321
    my ( $circ ) = @_;
321
    my ( $circ ) = @_;
322
    $circ->{'barcode'} = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && C4::Context->preference('itemBarcodeInputFilter'));
322
    $circ->{'barcode'} = barcodedecode($circ->{'barcode'}) if( $circ->{'barcode'} && (C4::Context->preference('itemBarcodeInputFilter') || C4::Context->preference('itembarcodelength')));
323
    my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
323
    my $item = GetBiblioFromItemNumber( undef, $circ->{ 'barcode' } );
324
    #warn( Data::Dumper->Dump( [ $circ, $item ], [ qw( circ item ) ] ) );
324
    #warn( Data::Dumper->Dump( [ $circ, $item ], [ qw( circ item ) ] ) );
325
    my $borrowernumber = _get_borrowernumber_from_barcode( $circ->{'barcode'} );
325
    my $borrowernumber = _get_borrowernumber_from_barcode( $circ->{'barcode'} );
(-)a/tools/import_borrowers.pl (-2 / +8 lines)
Lines 41-47 use C4::Auth; Link Here
41
use C4::Output;
41
use C4::Output;
42
use C4::Dates qw(format_date_in_iso);
42
use C4::Dates qw(format_date_in_iso);
43
use C4::Context;
43
use C4::Context;
44
use C4::Branch qw(GetBranchName);
44
use C4::Branch qw(GetBranchName GetBranches);
45
use C4::Members;
45
use C4::Members;
46
use C4::Members::Attributes qw(:all);
46
use C4::Members::Attributes qw(:all);
47
use C4::Members::AttributeTypes;
47
use C4::Members::AttributeTypes;
Lines 271-277 if ( $uploadborrowers && length($uploadborrowers) > 0 ) { Link Here
271
            # FIXME: fixup_cardnumber says to lock table, but the web interface doesn't so this doesn't either.
271
            # FIXME: fixup_cardnumber says to lock table, but the web interface doesn't so this doesn't either.
272
            # At least this is closer to AddMember than in members/memberentry.pl
272
            # At least this is closer to AddMember than in members/memberentry.pl
273
            if (!$borrower{'cardnumber'}) {
273
            if (!$borrower{'cardnumber'}) {
274
                $borrower{'cardnumber'} = fixup_cardnumber(undef);
274
              my $onlymine=(C4::Context->preference('IndependantBranches') &&
275
              C4::Context->userenv &&
276
              C4::Context->userenv->{flags} % 2 !=1  &&
277
              C4::Context->userenv->{branch}?1:0);
278
279
              my $branches=GetBranches($onlymine);
280
              $borrower{'cardnumber'} = fixup_cardnumber(undef,$branches->{$borrower{'branchcode'}});
275
            }
281
            }
276
            if ($borrowernumber = AddMember(%borrower)) {
282
            if ($borrowernumber = AddMember(%borrower)) {
277
                if ($extended) {
283
                if ($extended) {
(-)a/tools/inventory.pl (-1 / +6 lines)
Lines 150-155 if ($uploadbarcodes && length($uploadbarcodes)>0){ Link Here
150
    my $count=0;
150
    my $count=0;
151
    while (my $barcode=<$uploadbarcodes>){
151
    while (my $barcode=<$uploadbarcodes>){
152
        $barcode =~ s/\r?\n$//;
152
        $barcode =~ s/\r?\n$//;
153
        if(C4::Context->preference('itembarcodelength') && (length($barcode) < C4::Context->preference('itembarcodelength'))) {
154
                my $prefix = GetBranchDetail(C4::Context->userenv->{'branch'})->{'itembarcodeprefix'} ;
155
                my $padding = C4::Context->preference('itembarcodelength') - length($prefix) - length($barcode) ;
156
                $barcode = $prefix . '0' x $padding . $barcode if($padding >= 0) ;
157
        }
158
153
        if ($qwthdrawn->execute($barcode) &&$qwthdrawn->rows){
159
        if ($qwthdrawn->execute($barcode) &&$qwthdrawn->rows){
154
            push @errorloop, {'barcode'=>$barcode,'ERR_WTHDRAWN'=>1};
160
            push @errorloop, {'barcode'=>$barcode,'ERR_WTHDRAWN'=>1};
155
        }else{
161
        }else{
156
- 

Return to bug 7676