6 # This script checks for required updates to the database.
8 # Part of the Koha Library Software www.koha.org
9 # Licensed under the GPL.
12 # - Would also be a good idea to offer to do a backup at this time...
14 # NOTE: If you do something more than once in here, make it table driven.
23 # FIXME - The user might be installing a new database, so can't rely
24 # on /etc/koha.conf anyway.
31 %existingtables, # tables already in database
35 $type, $null, $key, $default, $extra,
36 $prefitem, # preference item in systempreferences table
43 my $dbh = C4::Context->dbh;
44 print "connected to your DB. Checking & modifying it\n" unless $silent;
49 # Tables to add if they don't exist
51 categorytable => "(categorycode char(5) NOT NULL default '',
52 description text default '',
53 itemtypecodes text default '',
54 PRIMARY KEY (categorycode)
56 subcategorytable => "(subcategorycode char(5) NOT NULL default '',
57 description text default '',
58 itemtypecodes text default '',
59 PRIMARY KEY (subcategorycode)
61 mediatypetable => "(mediatypecode char(5) NOT NULL default '',
62 description text default '',
63 itemtypecodes text default '',
64 PRIMARY KEY (mediatypecode)
67 `timestamp` TIMESTAMP NOT NULL ,
68 `user` INT( 11 ) NOT NULL ,
69 `module` TEXT default '',
70 `action` TEXT default '' ,
71 `object` INT(11) default '' ,
72 `info` TEXT default '' ,
73 PRIMARY KEY ( `timestamp` , `user` )
76 module varchar(20) NOT NULL default '',
77 code varchar(20) NOT NULL default '',
78 name varchar(100) NOT NULL default '',
79 title varchar(200) NOT NULL default '',
81 PRIMARY KEY (module,code)
84 alertid int(11) NOT NULL auto_increment,
85 borrowernumber int(11) NOT NULL default '0',
86 type varchar(10) NOT NULL default '',
87 externalid varchar(20) NOT NULL default '',
88 PRIMARY KEY (alertid),
89 KEY borrowernumber (borrowernumber),
90 KEY type (type,externalid)
95 subscription => { 'letter' => 'char(20) NULL'},
96 # tablename => { 'field' => 'fieldtype' },
99 my %dropable_table = (
100 # tablename => 'tablename',
103 my %uselessfields = (
104 # tablename => "field1,field2",
106 # the other hash contains other actions that can't be done elsewhere. they are done
107 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
109 # The tabledata hash contains data that should be in the tables.
110 # The uniquefieldrequired hash entry is used to determine which (if any) fields
111 # must not exist in the table for this row to be inserted. If the
112 # uniquefieldrequired entry is already in the table, the existing data is not
113 # modified, unless the forceupdate hash entry is also set. Fields in the
114 # anonymous "forceupdate" hash will be forced to be updated to the default
115 # values given in the %tabledata hash.
119 # { uniquefielrequired => 'fieldname', # the primary key in the table
120 # fieldname => fieldvalue,
121 # fieldname2 => fieldvalue2,
124 systempreferences => [
126 uniquefieldrequired => 'variable',
127 variable => 'Activate_Log',
129 forceupdate => { 'explanation' => 1,
131 explanation => 'Turn Log Actions on DB On an Off',
135 uniquefieldrequired => 'variable',
136 variable => 'ReturnBeforeExpiry',
138 forceupdate => { 'explanation' => 1,
140 explanation => 'If Yes, Returndate on issuing can\'t be after borrower card expiry',
144 uniquefieldrequired => 'variable',
145 variable => 'opacstylesheet',
147 forceupdate => { 'explanation' => 1,
149 explanation => 'Enter a complete URL to use an alternate stylesheet in OPAC',
153 uniquefieldrequired => 'variable',
154 variable => 'opacsmallimage',
156 forceupdate => { 'explanation' => 1,
158 explanation => 'Enter a complete URL to an image, will be on top/left instead of the Koha logo',
162 uniquefieldrequired => 'variable',
163 variable => 'opaclargeimage',
165 forceupdate => { 'explanation' => 1,
167 explanation => 'Enter a complete URL to an image, will be on the main page, instead of the Koha logo',
171 uniquefieldrequired => 'variable',
172 variable => 'delimiter',
174 forceupdate => { 'explanation' => 1,
176 explanation => 'separator for reports exported to spreadsheet',
180 uniquefieldrequired => 'variable',
182 value => 'OPENOFFICE.ORG',
183 forceupdate => { 'explanation' => 1,
186 explanation => 'Define the default application for report exportations into files',
188 options => 'EXCEL|OPENOFFICE.ORG'
191 uniquefieldrequired => 'variable',
192 variable => 'Delimiter',
194 forceupdate => { 'explanation' => 1,
197 explanation => 'Define the default separator character for report exportations into files',
199 options => ';|tabulation|,|/|\|#'
202 uniquefieldrequired => 'variable',
203 variable => 'SubscriptionHistory',
205 forceupdate => { 'explanation' => 1,
208 explanation => 'Define the information level for serials history in OPAC',
210 options => 'simplified|full'
213 uniquefieldrequired => 'variable',
214 variable => 'hidelostitems',
216 forceupdate => { 'explanation' => 1,
218 explanation => 'show or hide "lost" items in OPAC.',
225 my %fielddefinitions = (
227 # { field => 'fieldname',
228 # type => 'fieldtype',
241 # Get version of MySQL database engine.
242 my $mysqlversion = `mysqld --version`;
243 $mysqlversion =~ /Ver (\S*) /;
245 if ( $mysqlversion ge '3.23' ) {
246 print "Could convert to MyISAM database tables...\n" unless $silent;
249 #---------------------------------
252 # Collect all tables into a list
253 $sth = $dbh->prepare("show tables");
255 while ( my ($table) = $sth->fetchrow ) {
256 $existingtables{$table} = 1;
260 # Now add any missing tables
261 foreach $table ( keys %requiretables ) {
262 unless ( $existingtables{$table} ) {
263 print "Adding $table table...\n" unless $silent;
264 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
267 print "Error : $sth->errstr \n";
273 # now drop useless tables
274 foreach $table ( keys %dropable_table ) {
275 if ( $existingtables{$table} ) {
276 print "Dropping unused table $table\n" if $debug and not $silent;
277 $dbh->do("drop table $table");
279 print "Error : $dbh->errstr \n";
284 #---------------------------------
287 foreach $table ( keys %requirefields ) {
288 print "Check table $table\n" if $debug and not $silent;
289 $sth = $dbh->prepare("show columns from $table");
292 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
294 $types{$column} = $type;
296 foreach $column ( keys %{ $requirefields{$table} } ) {
297 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
298 if ( !$types{$column} ) {
300 # column doesn't exist
301 print "Adding $column field to $table table...\n" unless $silent;
302 $query = "alter table $table
303 add column $column " . $requirefields{$table}->{$column};
304 print "Execute: $query\n" if $debug;
305 my $sti = $dbh->prepare($query);
308 print "**Error : $sti->errstr \n";
315 foreach $table ( keys %fielddefinitions ) {
316 print "Check table $table\n" if $debug;
317 $sth = $dbh->prepare("show columns from $table");
320 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
322 $definitions->{$column}->{type} = $type;
323 $definitions->{$column}->{null} = $null;
324 $definitions->{$column}->{key} = $key;
325 $definitions->{$column}->{default} = $default;
326 $definitions->{$column}->{extra} = $extra;
328 my $fieldrow = $fielddefinitions{$table};
329 foreach my $row (@$fieldrow) {
330 my $field = $row->{field};
331 my $type = $row->{type};
332 my $null = $row->{null};
333 my $key = $row->{key};
334 my $default = $row->{default};
335 $default="''" unless $default;
336 my $extra = $row->{extra};
337 my $def = $definitions->{$field};
338 unless ( $type eq $def->{type}
339 && $null eq $def->{null}
340 && $key eq $def->{key}
341 && $default eq $def->{default}
342 && $extra eq $def->{extra} )
348 if ( $key eq 'PRI' ) {
349 $key = 'PRIMARY KEY';
351 unless ( $extra eq 'auto_increment' ) {
354 # if it's a new column use "add", if it's an old one, use "change".
356 if ($definitions->{$field}->{type}) {
357 $action="change $field"
361 # if it's a primary key, drop the previous pk, before altering the table
363 if ($key ne 'PRIMARY KEY') {
364 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
366 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
368 $sth->execute($default);
369 print " Alter $field in $table\n" unless $silent;
375 # Populate tables with required data
376 foreach my $table ( keys %tabledata ) {
377 print "Checking for data required in table $table...\n" unless $silent;
378 my $tablerows = $tabledata{$table};
379 foreach my $row (@$tablerows) {
380 my $uniquefieldrequired = $row->{uniquefieldrequired};
381 my $uniquevalue = $row->{$uniquefieldrequired};
382 my $forceupdate = $row->{forceupdate};
385 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
387 $sth->execute($uniquevalue);
389 foreach my $field (keys %$forceupdate) {
390 if ($forceupdate->{$field}) {
391 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
392 $sth->execute($row->{$field}, $uniquevalue);
396 print "Adding row to $table: " unless $silent;
400 foreach my $field ( keys %$row ) {
401 next if $field eq 'uniquefieldrequired';
402 next if $field eq 'forceupdate';
403 my $value = $row->{$field};
404 push @values, $value;
405 print " $field => $value" unless $silent;
406 $fieldlist .= "$field,";
407 $placeholders .= "?,";
409 print "\n" unless $silent;
410 $fieldlist =~ s/,$//;
411 $placeholders =~ s/,$//;
414 "insert into $table ($fieldlist) values ($placeholders)");
415 $sth->execute(@values);
420 # at last, remove useless fields
421 foreach $table ( keys %uselessfields ) {
422 my @fields = split /,/,$uselessfields{$table};
425 foreach my $fieldtodrop (@fields) {
426 $fieldtodrop =~ s/\t//g;
427 $fieldtodrop =~ s/\n//g;
429 $sth = $dbh->prepare("show columns from $table");
431 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
433 $exists =1 if ($column eq $fieldtodrop);
436 print "deleting $fieldtodrop field in $table...\n" unless $silent;
437 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
449 # Revision 1.117 2005/08/04 14:24:39 tipaul
450 # synch'ing 2.2 and head
452 # Revision 1.116 2005/08/04 08:55:54 tipaul
453 # Letters / alert system, continuing...
455 # * adding a package Letters.pm, that manages Letters & alerts.
456 # * adding feature : it's now possible to define a "letter" for any subscription created. If a letter is defined, users in OPAC can put an alert on the subscription. When an issue is marked "arrived", all users in the alert will recieve a mail (as defined in the "letter"). This last part (= send the mail) is not yet developped. (Should be done this week)
457 # * adding feature : it's now possible to "put to an alert" in OPAC, for any serial subscription. The alert is stored in a new table, called alert. An alert can be put only if the librarian has activated them in subscription (and they activate it just by choosing a "letter" to sent to borrowers on new issues)
458 # * adding feature : librarian can see in borrower detail which alerts they have put, and a user can see in opac-detail which alert they have put too.
460 # Note that the system should be generic enough to manage any type of alert.
461 # I plan to extend it soon to virtual shelves : a borrower will be able to put an alert on a virtual shelf, to be warned when something is changed in the virtual shelf (mail being sent once a day by cron, or manually by the shelf owner. Anyway, a mail won't be sent on every change, users would be spammed by Koha ;-) )
463 # Revision 1.115 2005/08/02 16:15:34 tipaul
464 # adding 2 fields to letter system :
465 # * module (acquisition, catalogue...) : it will be usefull to show the librarian only letters he may be interested by.
466 # * title, that will be used as mail subject.
468 # Revision 1.114 2005/07/28 15:10:13 tipaul
469 # Introducing new "Letters" system : Letters will be used everytime you want to sent something to someone (through mail or paper). For example, sending a mail for overdues use letter that you can put as parameters. Sending a mail to a borrower when a suggestion is validated uses a letter too.
470 # the letter table contains 3 fields :
471 # * code => the code of the letter
472 # * name => the complete name of the letter
473 # * content => the complete text. It's a TEXT field type, so has no limits.
475 # My next goal now is to work on point 2-I "serial issue alert"
476 # With this feature, in serials, a user can subscribe the "issue alert". For every issue arrived/missing, a mail is sent to all subscribers of this list. The mail warns the user that the issue is arrive or missing. Will be in head.
477 # (see mail on koha-devel, 2005/04/07)
479 # The "serial issue alert" will be the 1st to use this letter system that probably needs some tweaking ;-)
481 # Once it will be stabilised default letters (in any languages) could be added during installer to help the library begin with this new feature.
483 # Revision 1.113 2005/07/28 08:38:41 tipaul
484 # For instance, the return date does not rely on the borrower expiration date. A systempref will be added in Koha, to modify return date calculation schema :
485 # * ReturnBeforeExpiry = yes => return date can't be after expiry date
486 # * ReturnBeforeExpiry = no => return date can be after expiry date
488 # Revision 1.112 2005/07/26 08:19:47 hdl
489 # Adding IndependantBranches System preference variable in order to manage Branch independancy.
491 # Revision 1.111 2005/07/25 15:35:38 tipaul
492 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
493 # So, the updatedatabase script can highly be cleaned (90% removed).
494 # Let's play with the new Koha DB structure now ;-)
501 # This script checks for required updates to the database.
503 # Part of the Koha Library Software www.koha.org
504 # Licensed under the GPL.
507 # - Would also be a good idea to offer to do a backup at this time...
509 # NOTE: If you do something more than once in here, make it table driven.
518 # FIXME - The user might be installing a new database, so can't rely
519 # on /etc/koha.conf anyway.
526 %existingtables, # tables already in database
530 $type, $null, $key, $default, $extra,
531 $prefitem, # preference item in systempreferences table
538 my $dbh = C4::Context->dbh;
539 print "connected to your DB. Checking & modifying it\n" unless $silent;
544 # Tables to add if they don't exist
545 my %requiretables = (
546 categorytable => "(categorycode char(5) NOT NULL default '',
547 description text default '',
548 itemtypecodes text default '',
549 PRIMARY KEY (categorycode)
551 subcategorytable => "(subcategorycode char(5) NOT NULL default '',
552 description text default '',
553 itemtypecodes text default '',
554 PRIMARY KEY (subcategorycode)
556 mediatypetable => "(mediatypecode char(5) NOT NULL default '',
557 description text default '',
558 itemtypecodes text default '',
559 PRIMARY KEY (mediatypecode)
562 `timestamp` TIMESTAMP NOT NULL ,
563 `user` INT( 11 ) NOT NULL ,
564 `module` TEXT default '',
565 `action` TEXT default '' ,
566 `object` INT(11) default '' ,
567 `info` TEXT default '' ,
568 PRIMARY KEY ( `timestamp` , `user` )
572 my %requirefields = (
573 # tablename => { 'field' => 'fieldtype' },
576 my %dropable_table = (
577 # tablename => 'tablename',
580 my %uselessfields = (
581 # tablename => "field1,field2",
583 # the other hash contains other actions that can't be done elsewhere. they are done
584 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
586 # The tabledata hash contains data that should be in the tables.
587 # The uniquefieldrequired hash entry is used to determine which (if any) fields
588 # must not exist in the table for this row to be inserted. If the
589 # uniquefieldrequired entry is already in the table, the existing data is not
590 # modified, unless the forceupdate hash entry is also set. Fields in the
591 # anonymous "forceupdate" hash will be forced to be updated to the default
592 # values given in the %tabledata hash.
596 # { uniquefielrequired => 'fieldname', # the primary key in the table
597 # fieldname => fieldvalue,
598 # fieldname2 => fieldvalue2,
601 systempreferences => [
603 uniquefieldrequired => 'variable',
604 variable => 'Activate_Log',
606 forceupdate => { 'explanation' => 1,
608 explanation => 'Turn Log Actions on DB On an Off',
612 uniquefieldrequired => 'variable',
613 variable => 'IndependantBranches',
615 forceupdate => { 'explanation' => 1,
617 explanation => 'Turn Branch independancy management On an Off',
625 my %fielddefinitions = (
627 # { field => 'fieldname',
628 # type => 'fieldtype',
641 # Get version of MySQL database engine.
642 my $mysqlversion = `mysqld --version`;
643 $mysqlversion =~ /Ver (\S*) /;
645 if ( $mysqlversion ge '3.23' ) {
646 print "Could convert to MyISAM database tables...\n" unless $silent;
649 #---------------------------------
652 # Collect all tables into a list
653 $sth = $dbh->prepare("show tables");
655 while ( my ($table) = $sth->fetchrow ) {
656 $existingtables{$table} = 1;
660 # Now add any missing tables
661 foreach $table ( keys %requiretables ) {
662 unless ( $existingtables{$table} ) {
663 print "Adding $table table...\n" unless $silent;
664 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
667 print "Error : $sth->errstr \n";
673 # now drop useless tables
674 foreach $table ( keys %dropable_table ) {
675 if ( $existingtables{$table} ) {
676 print "Dropping unused table $table\n" if $debug and not $silent;
677 $dbh->do("drop table $table");
679 print "Error : $dbh->errstr \n";
684 #---------------------------------
687 foreach $table ( keys %requirefields ) {
688 print "Check table $table\n" if $debug and not $silent;
689 $sth = $dbh->prepare("show columns from $table");
692 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
694 $types{$column} = $type;
696 foreach $column ( keys %{ $requirefields{$table} } ) {
697 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
698 if ( !$types{$column} ) {
700 # column doesn't exist
701 print "Adding $column field to $table table...\n" unless $silent;
702 $query = "alter table $table
703 add column $column " . $requirefields{$table}->{$column};
704 print "Execute: $query\n" if $debug;
705 my $sti = $dbh->prepare($query);
708 print "**Error : $sti->errstr \n";
715 foreach $table ( keys %fielddefinitions ) {
716 print "Check table $table\n" if $debug;
717 $sth = $dbh->prepare("show columns from $table");
720 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
722 $definitions->{$column}->{type} = $type;
723 $definitions->{$column}->{null} = $null;
724 $definitions->{$column}->{key} = $key;
725 $definitions->{$column}->{default} = $default;
726 $definitions->{$column}->{extra} = $extra;
728 my $fieldrow = $fielddefinitions{$table};
729 foreach my $row (@$fieldrow) {
730 my $field = $row->{field};
731 my $type = $row->{type};
732 my $null = $row->{null};
733 my $key = $row->{key};
734 my $default = $row->{default};
735 $default="''" unless $default;
736 my $extra = $row->{extra};
737 my $def = $definitions->{$field};
738 unless ( $type eq $def->{type}
739 && $null eq $def->{null}
740 && $key eq $def->{key}
741 && $default eq $def->{default}
742 && $extra eq $def->{extra} )
748 if ( $key eq 'PRI' ) {
749 $key = 'PRIMARY KEY';
751 unless ( $extra eq 'auto_increment' ) {
754 # if it's a new column use "add", if it's an old one, use "change".
756 if ($definitions->{$field}->{type}) {
757 $action="change $field"
761 # if it's a primary key, drop the previous pk, before altering the table
763 if ($key ne 'PRIMARY KEY') {
764 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
766 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
768 $sth->execute($default);
769 print " Alter $field in $table\n" unless $silent;
775 # Populate tables with required data
776 foreach my $table ( keys %tabledata ) {
777 print "Checking for data required in table $table...\n" unless $silent;
778 my $tablerows = $tabledata{$table};
779 foreach my $row (@$tablerows) {
780 my $uniquefieldrequired = $row->{uniquefieldrequired};
781 my $uniquevalue = $row->{$uniquefieldrequired};
782 my $forceupdate = $row->{forceupdate};
785 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
787 $sth->execute($uniquevalue);
789 foreach my $field (keys %$forceupdate) {
790 if ($forceupdate->{$field}) {
791 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
792 $sth->execute($row->{$field}, $uniquevalue);
796 print "Adding row to $table: " unless $silent;
800 foreach my $field ( keys %$row ) {
801 next if $field eq 'uniquefieldrequired';
802 next if $field eq 'forceupdate';
803 my $value = $row->{$field};
804 push @values, $value;
805 print " $field => $value" unless $silent;
806 $fieldlist .= "$field,";
807 $placeholders .= "?,";
809 print "\n" unless $silent;
810 $fieldlist =~ s/,$//;
811 $placeholders =~ s/,$//;
814 "insert into $table ($fieldlist) values ($placeholders)");
815 $sth->execute(@values);
820 # at last, remove useless fields
821 foreach $table ( keys %uselessfields ) {
822 my @fields = split /,/,$uselessfields{$table};
825 foreach my $fieldtodrop (@fields) {
826 $fieldtodrop =~ s/\t//g;
827 $fieldtodrop =~ s/\n//g;
829 $sth = $dbh->prepare("show columns from $table");
831 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
833 $exists =1 if ($column eq $fieldtodrop);
836 print "deleting $fieldtodrop field in $table...\n" unless $silent;
837 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
849 # Revision 1.117 2005/08/04 14:24:39 tipaul
850 # synch'ing 2.2 and head
852 # Revision 1.116 2005/08/04 08:55:54 tipaul
853 # Letters / alert system, continuing...
855 # * adding a package Letters.pm, that manages Letters & alerts.
856 # * adding feature : it's now possible to define a "letter" for any subscription created. If a letter is defined, users in OPAC can put an alert on the subscription. When an issue is marked "arrived", all users in the alert will recieve a mail (as defined in the "letter"). This last part (= send the mail) is not yet developped. (Should be done this week)
857 # * adding feature : it's now possible to "put to an alert" in OPAC, for any serial subscription. The alert is stored in a new table, called alert. An alert can be put only if the librarian has activated them in subscription (and they activate it just by choosing a "letter" to sent to borrowers on new issues)
858 # * adding feature : librarian can see in borrower detail which alerts they have put, and a user can see in opac-detail which alert they have put too.
860 # Note that the system should be generic enough to manage any type of alert.
861 # I plan to extend it soon to virtual shelves : a borrower will be able to put an alert on a virtual shelf, to be warned when something is changed in the virtual shelf (mail being sent once a day by cron, or manually by the shelf owner. Anyway, a mail won't be sent on every change, users would be spammed by Koha ;-) )
863 # Revision 1.115 2005/08/02 16:15:34 tipaul
864 # adding 2 fields to letter system :
865 # * module (acquisition, catalogue...) : it will be usefull to show the librarian only letters he may be interested by.
866 # * title, that will be used as mail subject.
868 # Revision 1.114 2005/07/28 15:10:13 tipaul
869 # Introducing new "Letters" system : Letters will be used everytime you want to sent something to someone (through mail or paper). For example, sending a mail for overdues use letter that you can put as parameters. Sending a mail to a borrower when a suggestion is validated uses a letter too.
870 # the letter table contains 3 fields :
871 # * code => the code of the letter
872 # * name => the complete name of the letter
873 # * content => the complete text. It's a TEXT field type, so has no limits.
875 # My next goal now is to work on point 2-I "serial issue alert"
876 # With this feature, in serials, a user can subscribe the "issue alert". For every issue arrived/missing, a mail is sent to all subscribers of this list. The mail warns the user that the issue is arrive or missing. Will be in head.
877 # (see mail on koha-devel, 2005/04/07)
879 # The "serial issue alert" will be the 1st to use this letter system that probably needs some tweaking ;-)
881 # Once it will be stabilised default letters (in any languages) could be added during installer to help the library begin with this new feature.
883 # Revision 1.113 2005/07/28 08:38:41 tipaul
884 # For instance, the return date does not rely on the borrower expiration date. A systempref will be added in Koha, to modify return date calculation schema :
885 # * ReturnBeforeExpiry = yes => return date can't be after expiry date
886 # * ReturnBeforeExpiry = no => return date can be after expiry date
888 # Revision 1.112 2005/07/26 08:19:47 hdl
889 # Adding IndependantBranches System preference variable in order to manage Branch independancy.
891 # Revision 1.111 2005/07/25 15:35:38 tipaul
892 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
893 # So, the updatedatabase script can highly be cleaned (90% removed).
894 # Let's play with the new Koha DB structure now ;-)