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.
24 use MARC::File::XML ( BinaryEncoding => 'utf8' );
26 # FIXME - The user might be installing a new database, so can't rely
27 # on /etc/koha.conf anyway.
34 %existingtables, # tables already in database
38 $type, $null, $key, $default, $extra,
39 $prefitem, # preference item in systempreferences table
46 my $dbh = C4::Context->dbh;
47 print "connected to your DB. Checking & modifying it\n" unless $silent;
48 $|=1; # flushes output
53 # Tables to add if they don't exist
56 `timestamp` TIMESTAMP NOT NULL ,
57 `user` INT( 11 ) NOT NULL ,
58 `module` TEXT default '',
59 `action` TEXT default '' ,
60 `object` INT(11) NULL ,
61 `info` TEXT default '' ,
62 PRIMARY KEY ( `timestamp` , `user` )
65 module varchar(20) NOT NULL default '',
66 code varchar(20) NOT NULL default '',
67 name varchar(100) NOT NULL default '',
68 title varchar(200) NOT NULL default '',
70 PRIMARY KEY (module,code)
73 alertid int(11) NOT NULL auto_increment,
74 borrowernumber int(11) NOT NULL default '0',
75 type varchar(10) NOT NULL default '',
76 externalid varchar(20) NOT NULL default '',
77 PRIMARY KEY (alertid),
78 KEY borrowernumber (borrowernumber),
79 KEY type (type,externalid)
82 `idnew` int(10) unsigned NOT NULL auto_increment,
83 `title` varchar(250) NOT NULL default '',
85 `lang` varchar(4) NOT NULL default '',
86 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
89 repeatable_holidays => "(
90 `id` int(11) NOT NULL auto_increment,
91 `branchcode` varchar(4) NOT NULL default '',
92 `weekday` smallint(6) default NULL,
93 `day` smallint(6) default NULL,
94 `month` smallint(6) default NULL,
95 `title` varchar(50) NOT NULL default '',
96 `description` text NOT NULL,
99 special_holidays => "(
100 `id` int(11) NOT NULL auto_increment,
101 `branchcode` varchar(4) NOT NULL default '',
102 `day` smallint(6) NOT NULL default '0',
103 `month` smallint(6) NOT NULL default '0',
104 `year` smallint(6) NOT NULL default '0',
105 `isexception` smallint(1) NOT NULL default '1',
106 `title` varchar(50) NOT NULL default '',
107 `description` text NOT NULL,
110 overduerules =>"(`branchcode` varchar(255) NOT NULL default '',
111 `categorycode` char(2) NOT NULL default '',
112 `delay1` int(4) default '0',
113 `letter1` varchar(20) default NULL,
114 `debarred1` char(1) default '0',
115 `delay2` int(4) default '0',
116 `debarred2` char(1) default '0',
117 `letter2` varchar(20) default NULL,
118 `delay3` int(4) default '0',
119 `letter3` varchar(20) default NULL,
120 `debarred3` int(1) default '0',
121 PRIMARY KEY (`branchcode`,`categorycode`)
123 cities => "(`cityid` int auto_increment,
124 `city_name` char(100) NOT NULL,
125 `city_zipcode` char(20),
126 PRIMARY KEY (`cityid`)
128 roadtype => "(`roadtypeid` int auto_increment,
129 `road_type` char(100) NOT NULL,
130 PRIMARY KEY (`roadtypeid`)
134 labelid int(11) NOT NULL auto_increment,
135 itemnumber varchar(100) NOT NULL default '',
136 timestamp timestamp(14) NOT NULL,
137 PRIMARY KEY (labelid)
141 id int(4) NOT NULL auto_increment,
142 barcodetype char(100) default '',
143 title tinyint(1) default '0',
144 isbn tinyint(1) default '0',
145 itemtype tinyint(1) default '0',
146 barcode tinyint(1) default '0',
147 dewey tinyint(1) default '0',
148 class tinyint(1) default '0',
149 author tinyint(1) default '0',
150 papertype char(100) default '',
151 startrow int(2) default NULL,
155 reviewid integer NOT NULL auto_increment,
156 borrowernumber integer,
157 biblionumber integer,
160 datereviewed datetime,
161 PRIMARY KEY (reviewid)
163 subscriptionroutinglist=>"(
164 routingid integer NOT NULL auto_increment,
165 borrowernumber integer,
167 subscriptionid integer,
168 PRIMARY KEY (routingid)
172 notify_id int(11) NOT NULL default '0',
173 `borrowernumber` int(11) NOT NULL default '0',
174 `itemnumber` int(11) NOT NULL default '0',
175 `notify_date` date NOT NULL default '0000-00-00',
176 `notify_send_date` date default NULL,
177 `notify_level` int(1) NOT NULL default '0',
178 `method` varchar(20) NOT NULL default ''
182 `charge_id` varchar(5) NOT NULL default '',
183 `description` text NOT NULL,
184 `amount` decimal(28,6) NOT NULL default '0.000000',
185 `min` int(4) NOT NULL default '0',
186 `max` int(4) NOT NULL default '0',
187 `level` int(1) NOT NULL default '0',
188 PRIMARY KEY (`charge_id`)
191 `entry` varchar(255) NOT NULL default '',
192 `weight` bigint(20) NOT NULL default '0',
193 PRIMARY KEY (`entry`)
197 `id` int NOT NULL auto_increment,
198 `biblio_auth_number` int NOT NULL,
199 `operation` char(20) NOT NULL,
200 `server` char(20) NOT NULL ,
202 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1",
206 my %requirefields = (
207 subscription => { 'letter' => 'char(20) NULL', 'distributedto' => 'text NULL', 'firstacquidate'=>'date NOT NULL','irregularity'=>'TEXT NULL default \'\'','numberpattern'=>'TINYINT(3) NULL default 0', 'callnumber'=>'text NULL', 'hemisphere' =>'TINYINT(3) NULL default 0', 'issuesatonce'=>'TINYINT(3) NOT NULL default 1', 'branchcode' =>'varchar(12) NOT NULL default \'\'', 'manualhistory'=>'TINYINT(1) NOT NULL default 0','internalnotes'=>'LONGTEXT NULL default \'\''},
208 itemtypes => { 'imageurl' => 'char(200) NULL'},
209 aqbookfund => { 'branchcode' => 'varchar(4) NULL'},
210 aqbudget => { 'branchcode' => 'varchar(4) NULL'},
211 auth_header => { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
212 auth_subfield_structure =>{ 'hidden' => 'TINYINT(3) NOT NULL default 0', 'kohafield' => 'VARCHAR(45) NOT NULL', 'linkid' => 'TINYINT(1) NOT NULL default 0', 'isurl' => 'TINYINT(1)', 'frameworkcode'=>'VARCHAR(8) NOT NULL'},
213 marc_breeding => { 'isbn' => 'varchar(13) NOT NULL'},
214 serial =>{ 'publisheddate' => 'date', 'claimdate' => 'date', 'itemnumber'=>'text NULL','routingnotes'=>'text NULL',},
215 statistics => { 'associatedborrower' => 'integer'},
216 z3950servers =>{ "name" =>"text", "description" => "text NOT NULL",
217 "position" =>"enum('primary','secondary','') NOT NULL default 'primary'", "icon" =>"text",
218 "type" =>"enum('zed','opensearch') NOT NULL default 'zed'",
220 issues =>{ 'issuedate'=>"date NOT NULL default '0000-00-00'", },
222 # tablename => { 'field' => 'fieldtype' },
225 # Enter here the table to delete.
226 my @TableToDelete = qw(
233 my %uselessfields = (
234 # tablename => "field1,field2",
235 borrowers => "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
236 deletedborrowers=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
238 # the other hash contains other actions that can't be done elsewhere. they are done
239 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
241 # The tabledata hash contains data that should be in the tables.
242 # The uniquefieldrequired hash entry is used to determine which (if any) fields
243 # must not exist in the table for this row to be inserted. If the
244 # uniquefieldrequired entry is already in the table, the existing data is not
245 # modified, unless the forceupdate hash entry is also set. Fields in the
246 # anonymous "forceupdate" hash will be forced to be updated to the default
247 # values given in the %tabledata hash.
251 # { uniquefielrequired => 'fieldname', # the primary key in the table
252 # fieldname => fieldvalue,
253 # fieldname2 => fieldvalue2,
256 systempreferences => [
258 uniquefieldrequired => 'variable',
259 variable => 'useDaysMode',
261 forceupdate => { 'explanation' => 1,
263 explanation => 'How to calculate return dates : Calendar means holidays will be controled, Days means the return date don\'t depend on holidays',
265 options => 'Calendar|Days'
268 uniquefieldrequired => 'variable',
269 variable => 'BorrowersTitles',
270 value => 'Mr|Mrs|Miss|Ms',
271 forceupdate => { 'explanation' => 1,
273 explanation => 'List all Titles for borrowers',
277 uniquefieldrequired => 'variable',
278 variable => 'BorrowerMandatoryField',
279 value => 'cardnumber|surname|address',
280 forceupdate => { 'explanation' => 1,
282 explanation => 'List all mandatory fields for borrowers',
286 uniquefieldrequired => 'variable',
287 variable => 'borrowerRelationship',
288 value => 'father|mother,grand-mother',
289 forceupdate => { 'explanation' => 1,
291 explanation => 'The relationships between a guarantor & a guarantee (separated by | or ,)',
295 uniquefieldrequired => 'variable',
296 variable => 'ReservesMaxPickUpDelay',
298 forceupdate => { 'explanation' => 1,
300 explanation => 'Maximum delay to pick up a reserved document',
304 uniquefieldrequired => 'variable',
305 variable => 'TransfersMaxDaysWarning',
307 forceupdate => { 'explanation' => 1,
309 explanation => 'Max delay before considering the transfer has potentialy a problem',
313 uniquefieldrequired => 'variable',
314 variable => 'memberofinstitution',
316 forceupdate => { 'explanation' => 1,
318 explanation => 'Are your patrons members of institutions',
322 uniquefieldrequired => 'variable',
323 variable => 'ReadingHistory',
325 forceupdate => { 'explanation' => 1,
327 explanation => 'Allow reading record info retrievable from issues and oldissues tables',
331 uniquefieldrequired => 'variable',
332 variable => 'IssuingInProcess',
334 forceupdate => { 'explanation' => 1,
336 explanation => 'Allow no debt alert if the patron is issuing item that accumulate debt',
340 uniquefieldrequired => 'variable',
341 variable => 'AutomaticItemReturn',
343 forceupdate => { 'explanation' => 1,
345 explanation => 'This Variable allow or not to return automaticly to his homebranch',
349 uniquefieldrequired => 'variable',
350 variable => 'reviewson',
352 forceupdate => { 'explanation' => 1,
354 explanation => 'Allows patrons to submit reviews from the opac',
358 uniquefieldrequired => 'variable',
359 variable => 'intranet_includes',
361 forceupdate => { 'explanation' => 1,
363 explanation => 'The includes directory you want for specific look of Koha (includes or includes_npl for example)',
367 uniquefieldrequired => 'variable',
368 variable => 'AutoLocation',
370 forceupdate => { 'explanation' => 1,
372 explanation => 'switch to activate or not Autolocation, if Yes, the Librarian can\'t change his location, it\'s defined by branchip',
376 uniquefieldrequired => 'variable',
377 variable => 'serialsadditems',
383 explanation => 'If set, a new item will be automatically added when receiving an issue',
387 uniquefieldrequired => 'variable',
388 variable => 'expandedSearchOption',
394 explanation => 'search among marc field',
398 uniquefieldrequired => 'variable',
399 variable => 'RequestOnOpac',
401 forceupdate => { 'explanation' => 1,
403 explanation => 'option to allow reserves on opac',
407 uniquefieldrequired => 'variable',
408 variable => 'OpacCloud',
410 forceupdate => { 'explanation' => 1,
412 explanation => 'Enable / Disable cloud link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
416 uniquefieldrequired => 'variable',
417 variable => 'OpacBrowser',
419 forceupdate => { 'explanation' => 1,
421 explanation => 'Enable/Disable browser link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
425 uniquefieldrequired => 'variable',
426 variable => 'OpacTopissue',
428 forceupdate => { 'explanation' => 1,
430 explanation => 'Enable / Disable the top issue link on OPAC',
434 uniquefieldrequired => 'variable',
435 variable => 'OpacAuthorities',
437 forceupdate => { 'explanation' => 1,
439 explanation => 'Enable / Disable the search authority link on OPAC',
443 uniquefieldrequired => 'variable',
444 variable => 'CataloguingLog',
446 forceupdate => {'explanation' => 1, 'type' => 1},
447 explanation => 'Active this if you want to log cataloguing action.',
451 uniquefieldrequired => 'variable',
452 variable => 'BorrowersLog',
454 forceupdate => {'explanation' => 1, 'type' => 1},
455 explanation => 'Active this if you want to log borrowers edition/creation/deletion...',
459 uniquefieldrequired => 'variable',
460 variable => 'SubscriptionLog',
462 forceupdate => {'explanation' => 1, 'type' => 1},
463 explanation => 'Active this if you want to log Subscription action',
467 uniquefieldrequired => 'variable',
468 variable => 'IssueLog',
470 forceupdate => {'explanation' => 1, 'type' => 1},
471 explanation => 'Active this if you want to log issue.',
475 uniquefieldrequired => 'variable',
476 variable => 'ReturnLog',
478 forceupdate => {'explanation' => 1, 'type' => 1},
479 explanation => 'Active this if you want to log the circulation return',
483 uniquefieldrequired => 'variable',
484 variable => 'Version',
486 forceupdate => {'explanation' => 1, 'type' => 1},
487 explanation => 'Koha Version',
491 uniquefieldrequired => 'variable',
492 variable => 'LetterLog',
494 forceupdate => {'explanation' => 1, 'type' => 1},
495 explanation => 'Active this if you want to log all the letter sent',
499 uniquefieldrequired => 'variable',
500 variable => 'FinesLog',
502 forceupdate => {'explanation' => 1, 'type' => 1},
503 explanation => 'Active this if you want to log fines',
507 uniquefieldrequired => 'variable',
508 variable => 'NoZebra',
510 forceupdate => {'explanation' => 1, 'type' => 1},
511 explanation => 'Active this if you want NOT to use zebra (large libraries should avoid this parameters)',
515 uniquefieldrequired => 'variable',
516 variable => 'NoZebraIndexes',
518 forceupdate => {'explanation' => 1, 'type' => 1},
519 explanation => "Enter a specific hash for NoZebra indexes. Enter : 'indexname' => '100a,245a,500*','index2' => '...'",
525 uniquefieldrequired => 'bit',
527 flag => 'editauthorities',
528 flagdesc => 'allow to edit authorities',
532 uniquefieldrequired => 'bit',
535 flagdesc => 'allow to manage serials subscriptions',
539 uniquefieldrequired => 'bit',
542 flagdesc => 'allow to access to the reports module',
546 authorised_values => [
548 uniquefieldrequired => 'id',
549 category => 'SUGGEST',
550 authorised_value => 'Not enough budget',
551 lib => 'This book it too much expensive',
556 my %fielddefinitions = (
558 # { field => 'fieldname',
559 # type => 'fieldtype',
567 field => 'booksellerid',
582 extra => 'auto_increment',
585 field => 'listprice',
586 type => 'varchar(10)',
593 field => 'invoiceprice',
594 type => 'varchar(10)',
604 field => 'notify_id',
612 field => 'notify_level',
623 { field => 'firstname',
627 { field => 'initials',
631 { field => 'B_email',
634 after => 'B_zipcode',
637 field => 'streetnumber', # street number (hidden if streettable table is empty)
643 field => 'streettype', # street table, list builded from a system table
646 after => 'streetnumber',
653 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
659 field => 'B_streettype', # street table, list builded from a system table
662 after => 'B_streetnumber',
671 field => 'address2', # complement address
683 field => 'contactfirstname', # contact's firstname
686 after => 'contactname',
689 field => 'contacttitle', # contact's title
692 after => 'contactfirstname',
695 field => 'branchcode',
696 type => 'varchar(10)',
702 field => 'categorycode',
703 type => 'varchar(10)',
713 type => 'varchar(25)',
721 type => 'varchar(4)',
729 type => 'varchar(30)',
735 deletedbiblioitems => [
738 type => 'varchar(30)',
747 type => 'varchar(15)',
754 field => 'branchprinter',
755 type => 'varchar(100)',
762 field => 'branchcode',
763 type => 'varchar(10)',
771 field => 'frombranch',
772 type => 'VARCHAR(10)',
780 type => 'VARCHAR(10)',
789 field => 'category_type',
797 field => 'categorycode',
798 type => 'varchar(10)',
806 deletedborrowers => [
807 { field => 'firstname',
811 { field => 'initials',
815 { field => 'B_email',
818 after => 'B_zipcode',
821 field => 'streetnumber', # street number (hidden if streettable table is empty)
827 field => 'streettype', # street table, list builded from a system table
830 after => 'streetnumber',
837 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
843 field => 'B_streettype', # street table, list builded from a system table
846 after => 'B_streetnumber',
855 field => 'address2', # complement address
867 field => 'contactfirstname', # contact's firstname
870 after => 'contactname',
873 field => 'contacttitle', # contact's title
876 after => 'contactfirstname',
882 field => 'borrowernumber',
884 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
890 field => 'itemnumber',
892 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
898 field => 'branchcode',
899 type => 'varchar(10)',
906 field => 'issuedate',
910 default => '0000-00-00',
921 default => '0000-00-00',
925 field => 'cutterextra',
926 type => 'varchar(45)',
933 field => 'issue_date',
941 field => 'homebranch',
942 type => 'varchar(10)',
949 field => 'holdingbranch',
950 type => 'varchar(10)',
958 type => 'varchar(10)',
968 type => 'varchar(10)',
991 marc_subfield_structure => [
993 field => 'defaultvalue',
1002 field => 'expirationdate',
1019 field => 'waitingdate',
1039 field => 'dateadded',
1040 type => 'timestamp',
1044 systempreferences => [
1054 field => 'explanation',
1076 # { indexname => 'index detail'
1080 { indexname => 'PRIMARY',
1086 { indexname => 'booksellerid',
1087 content => 'booksellerid',
1091 { indexname => 'basketno',
1092 content => 'basketno',
1095 aqorderbreakdown => [
1096 { indexname => 'ordernumber',
1097 content => 'ordernumber',
1099 { indexname => 'bookfundid',
1100 content => 'bookfundid',
1104 { indexname => 'isbn',
1107 { indexname => 'publishercode',
1108 content => 'publishercode',
1113 indexname => 'branchcode',
1114 content => 'branchcode',
1118 branchrelations => [
1120 indexname => 'PRIMARY',
1121 content => 'categorycode',
1125 branchrelations => [
1126 { indexname => 'PRIMARY',
1127 content => 'branchcode,categorycode',
1130 { indexname => 'branchcode',
1131 content => 'branchcode',
1133 { indexname => 'categorycode',
1134 content => 'categorycode',
1138 { indexname => 'PRIMARY',
1139 content => 'currency',
1145 indexname => 'categorycode',
1146 content => 'categorycode',
1150 { indexname => 'homebranch',
1151 content => 'homebranch',
1153 { indexname => 'holdingbranch',
1154 content => 'holdingbranch',
1159 indexname => 'itemtype',
1160 content => 'itemtype',
1164 { indexname => 'shelfnumber',
1165 content => 'shelfnumber',
1167 { indexname => 'itemnumber',
1168 content => 'itemnumber',
1172 { indexname => 'PRIMARY',
1179 my %foreign_keys = (
1181 # { key => 'the key in table' (must be indexed)
1182 # foreigntable => 'the foreigntable name', # (the parent)
1183 # foreignkey => 'the foreign key column(s)' # (in the parent)
1184 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1185 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1188 branchrelations => [
1189 { key => 'branchcode',
1190 foreigntable => 'branches',
1191 foreignkey => 'branchcode',
1192 onUpdate => 'CASCADE',
1193 onDelete => 'CASCADE',
1195 { key => 'categorycode',
1196 foreigntable => 'branchcategories',
1197 foreignkey => 'categorycode',
1198 onUpdate => 'CASCADE',
1199 onDelete => 'CASCADE',
1203 { key => 'shelfnumber',
1204 foreigntable => 'bookshelf',
1205 foreignkey => 'shelfnumber',
1206 onUpdate => 'CASCADE',
1207 onDelete => 'CASCADE',
1209 { key => 'itemnumber',
1210 foreigntable => 'items',
1211 foreignkey => 'itemnumber',
1212 onUpdate => 'CASCADE',
1213 onDelete => 'CASCADE',
1216 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1217 # easily deleted, but branches/itemtype not too easy to empty...
1219 { key => 'biblionumber',
1220 foreigntable => 'biblio',
1221 foreignkey => 'biblionumber',
1222 onUpdate => 'CASCADE',
1223 onDelete => 'CASCADE',
1225 { key => 'itemtype',
1226 foreigntable => 'itemtypes',
1227 foreignkey => 'itemtype',
1228 onUpdate => 'CASCADE',
1229 onDelete => 'RESTRICT',
1233 { key => 'biblioitemnumber',
1234 foreigntable => 'biblioitems',
1235 foreignkey => 'biblioitemnumber',
1236 onUpdate => 'CASCADE',
1237 onDelete => 'CASCADE',
1239 { key => 'homebranch',
1240 foreigntable => 'branches',
1241 foreignkey => 'branchcode',
1242 onUpdate => 'CASCADE',
1243 onDelete => 'RESTRICT',
1245 { key => 'holdingbranch',
1246 foreigntable => 'branches',
1247 foreignkey => 'branchcode',
1248 onUpdate => 'CASCADE',
1249 onDelete => 'RESTRICT',
1253 { key => 'booksellerid',
1254 foreigntable => 'aqbooksellers',
1256 onUpdate => 'CASCADE',
1257 onDelete => 'RESTRICT',
1261 { key => 'basketno',
1262 foreigntable => 'aqbasket',
1263 foreignkey => 'basketno',
1264 onUpdate => 'CASCADE',
1265 onDelete => 'CASCADE',
1267 { key => 'biblionumber',
1268 foreigntable => 'biblio',
1269 foreignkey => 'biblionumber',
1270 onUpdate => 'SET NULL',
1271 onDelete => 'SET NULL',
1275 { key => 'listprice',
1276 foreigntable => 'currency',
1277 foreignkey => 'currency',
1278 onUpdate => 'CASCADE',
1279 onDelete => 'CASCADE',
1281 { key => 'invoiceprice',
1282 foreigntable => 'currency',
1283 foreignkey => 'currency',
1284 onUpdate => 'CASCADE',
1285 onDelete => 'CASCADE',
1288 aqorderbreakdown => [
1289 { key => 'ordernumber',
1290 foreigntable => 'aqorders',
1291 foreignkey => 'ordernumber',
1292 onUpdate => 'CASCADE',
1293 onDelete => 'CASCADE',
1295 { key => 'bookfundid',
1296 foreigntable => 'aqbookfund',
1297 foreignkey => 'bookfundid',
1298 onUpdate => 'CASCADE',
1299 onDelete => 'CASCADE',
1302 branchtransfers => [
1303 { key => 'frombranch',
1304 foreigntable => 'branches',
1305 foreignkey => 'branchcode',
1306 onUpdate => 'CASCADE',
1307 onDelete => 'CASCADE',
1309 { key => 'tobranch',
1310 foreigntable => 'branches',
1311 foreignkey => 'branchcode',
1312 onUpdate => 'CASCADE',
1313 onDelete => 'CASCADE',
1315 { key => 'itemnumber',
1316 foreigntable => 'items',
1317 foreignkey => 'itemnumber',
1318 onUpdate => 'CASCADE',
1319 onDelete => 'CASCADE',
1323 { key => 'categorycode',
1324 foreigntable => 'categories',
1325 foreignkey => 'categorycode',
1326 onUpdate => 'CASCADE',
1327 onDelete => 'CASCADE',
1329 { key => 'itemtype',
1330 foreigntable => 'itemtypes',
1331 foreignkey => 'itemtype',
1332 onUpdate => 'CASCADE',
1333 onDelete => 'CASCADE',
1336 issues => [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1338 { key => 'borrowernumber',
1339 foreigntable => 'borrowers',
1340 foreignkey => 'borrowernumber',
1341 onUpdate => 'SET NULL',
1342 onDelete => 'SET NULL',
1344 { key => 'itemnumber',
1345 foreigntable => 'items',
1346 foreignkey => 'itemnumber',
1347 onUpdate => 'SET NULL',
1348 onDelete => 'SET NULL',
1352 { key => 'borrowernumber',
1353 foreigntable => 'borrowers',
1354 foreignkey => 'borrowernumber',
1355 onUpdate => 'CASCADE',
1356 onDelete => 'CASCADE',
1358 { key => 'biblionumber',
1359 foreigntable => 'biblio',
1360 foreignkey => 'biblionumber',
1361 onUpdate => 'CASCADE',
1362 onDelete => 'CASCADE',
1364 { key => 'itemnumber',
1365 foreigntable => 'items',
1366 foreignkey => 'itemnumber',
1367 onUpdate => 'CASCADE',
1368 onDelete => 'CASCADE',
1370 { key => 'branchcode',
1371 foreigntable => 'branches',
1372 foreignkey => 'branchcode',
1373 onUpdate => 'CASCADE',
1374 onDelete => 'CASCADE',
1377 borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1378 # but prevent deleting a branch as soon as it has 1 borrower !
1379 { key => 'categorycode',
1380 foreigntable => 'categories',
1381 foreignkey => 'categorycode',
1382 onUpdate => 'RESTRICT',
1383 onDelete => 'RESTRICT',
1385 { key => 'branchcode',
1386 foreigntable => 'branches',
1387 foreignkey => 'branchcode',
1388 onUpdate => 'RESTRICT',
1389 onDelete => 'RESTRICT',
1392 deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1393 # but prevent deleting a branch as soon as it has 1 borrower !
1394 { key => 'categorycode',
1395 foreigntable => 'categories',
1396 foreignkey => 'categorycode',
1397 onUpdate => 'RESTRICT',
1398 onDelete => 'RESTRICT',
1400 { key => 'branchcode',
1401 foreigntable => 'branches',
1402 foreignkey => 'branchcode',
1403 onUpdate => 'RESTRICT',
1404 onDelete => 'RESTRICT',
1408 { key => 'borrowernumber',
1409 foreigntable => 'borrowers',
1410 foreignkey => 'borrowernumber',
1411 onUpdate => 'CASCADE',
1412 onDelete => 'CASCADE',
1414 { key => 'itemnumber',
1415 foreigntable => 'items',
1416 foreignkey => 'itemnumber',
1417 onUpdate => 'SET NULL',
1418 onDelete => 'SET NULL',
1421 auth_tag_structure => [
1422 { key => 'authtypecode',
1423 foreigntable => 'auth_types',
1424 foreignkey => 'authtypecode',
1425 onUpdate => 'CASCADE',
1426 onDelete => 'CASCADE',
1429 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1434 my %column_change = (
1438 from => 'emailaddress',
1443 from => 'streetaddress',
1445 after => 'initials',
1448 from => 'faxnumber',
1453 from => 'textmessaging',
1459 to => 'contactnote',
1460 after => 'opacnote',
1463 from => 'physstreet',
1468 from => 'streetcity',
1470 after => 'B_address',
1483 from => 'homezipcode',
1490 after => 'B_zipcode',
1495 after => 'dateenrolled',
1498 from => 'guarantor',
1499 to => 'guarantorid',
1500 after => 'contactname',
1503 from => 'altrelationship',
1504 to => 'relationship',
1505 after => 'borrowernotes',
1509 deletedborrowers => [
1511 from => 'emailaddress',
1516 from => 'streetaddress',
1518 after => 'initials',
1521 from => 'faxnumber',
1526 from => 'textmessaging',
1532 to => 'contactnote',
1533 after => 'opacnote',
1536 from => 'physstreet',
1541 from => 'streetcity',
1543 after => 'B_address',
1556 from => 'homezipcode',
1563 after => 'B_zipcode',
1568 after => 'dateenrolled',
1571 from => 'guarantor',
1572 to => 'guarantorid',
1573 after => 'contactname',
1576 from => 'altrelationship',
1577 to => 'relationship',
1578 after => 'borrowernotes',
1584 # MOVE all tables TO UTF-8 and innoDB
1585 $sth = $dbh->prepare("show table status");
1587 while ( my $table = $sth->fetchrow_hashref ) {
1588 next if $table->{Name} eq 'marc_word';
1589 next if $table->{Name} eq 'marc_subfield_table';
1590 next if $table->{Name} eq 'auth_word';
1591 next if $table->{Name} eq 'auth_subfield_table';
1592 if ($table->{Engine} ne 'InnoDB') {
1593 $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1594 print "moving $table->{Name} to InnoDB\n";
1596 unless ($table->{Collation} =~ /^utf8/) {
1597 print "moving $table->{Name} to utf8\n";
1598 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1599 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1600 # FIXME : maybe a ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 would be better, def char set seems to work fine. If any problem encountered, let's try with convert !
1606 foreach my $table (keys %column_change) {
1607 $sth = $dbh->prepare("show columns from $table");
1610 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1612 $types{$column}->{type} ="$type";
1613 $types{$column}->{null} = "$null";
1614 $types{$column}->{key} = "$key";
1615 $types{$column}->{default} = "$default";
1616 $types{$column}->{extra} = "$extra";
1618 my $tablerows = $column_change{$table};
1619 foreach my $row ( @$tablerows ) {
1620 if ($types{$row->{from}}->{type}) {
1621 print "altering $table $row->{from} to $row->{to}\n";
1622 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1623 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
1625 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1626 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1627 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1628 "$types{$row->{from}}->{extra} after $row->{after} ";
1635 # Enter here the field you want to delete from DB.
1636 # FIXME :: there is a %uselessfield before which seems doing the same things.
1637 my %fieldtodelete = (
1638 # tablename => [fieldname1,fieldname2,...]
1642 print "removing some unused fields...\n";
1643 foreach my $table ( keys %fieldtodelete ) {
1644 foreach my $field ( @{$fieldtodelete{$table}} ){
1645 print "removing ".$field." from ".$table;
1646 my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1649 print "Error : $sth->errstr \n";
1654 # Enter here the line you want to remove from DB.
1655 my %linetodelete = (
1656 # table name => where clause.
1657 userflags => "bit = 8", # delete the 'reserveforself' flags
1661 #-------------------
1666 # Get version of MySQL database engine.
1667 my $mysqlversion = `mysqld --version`;
1668 $mysqlversion =~ /Ver (\S*) /;
1670 if ( $mysqlversion ge '3.23' ) {
1671 print "Could convert to MyISAM database tables...\n" unless $silent;
1674 #---------------------------------
1677 # Collect all tables into a list
1678 $sth = $dbh->prepare("show tables");
1680 while ( my ($table) = $sth->fetchrow ) {
1681 $existingtables{$table} = 1;
1685 # Now add any missing tables
1686 foreach $table ( keys %requiretables ) {
1687 unless ( $existingtables{$table} ) {
1688 print "Adding $table table...\n" unless $silent;
1689 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1692 print "Error : $sth->errstr \n";
1698 #---------------------------------
1701 foreach $table ( keys %requirefields ) {
1702 print "Check table $table\n" if $debug and not $silent;
1703 $sth = $dbh->prepare("show columns from $table");
1706 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1708 $types{$column} = $type;
1710 foreach $column ( keys %{ $requirefields{$table} } ) {
1711 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1712 if ( !$types{$column} ) {
1714 # column doesn't exist
1715 print "Adding $column field to $table table...\n" unless $silent;
1716 $query = "alter table $table
1717 add column $column " . $requirefields{$table}->{$column};
1718 print "Execute: $query\n" if $debug;
1719 my $sti = $dbh->prepare($query);
1722 print "**Error : $sti->errstr \n";
1729 foreach $table ( keys %fielddefinitions ) {
1730 print "Check table $table\n" if $debug;
1731 $sth = $dbh->prepare("show columns from $table");
1734 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1736 $definitions->{$column}->{type} = $type;
1737 $definitions->{$column}->{null} = $null;
1738 $definitions->{$column}->{null} = 'NULL' if $null eq 'YES';
1739 $definitions->{$column}->{key} = $key;
1740 $definitions->{$column}->{default} = $default;
1741 $definitions->{$column}->{extra} = $extra;
1743 my $fieldrow = $fielddefinitions{$table};
1744 foreach my $row (@$fieldrow) {
1745 my $field = $row->{field};
1746 my $type = $row->{type};
1747 my $null = $row->{null};
1748 # $null = 'YES' if $row->{null} eq 'NULL';
1749 my $key = $row->{key};
1750 my $default = $row->{default};
1751 # $default="''" unless $default;
1752 my $extra = $row->{extra};
1753 my $def = $definitions->{$field};
1754 my $after = ($row->{after}?" after ".$row->{after}:"");
1756 unless ( $type eq $def->{type}
1757 && $null eq $def->{null}
1758 && $key eq $def->{key}
1759 && $extra eq $def->{extra} )
1761 if ( $null eq '' ) {
1764 if ( $key eq 'PRI' ) {
1765 $key = 'PRIMARY KEY';
1767 unless ( $extra eq 'auto_increment' ) {
1771 # if it's a new column use "add", if it's an old one, use "change".
1773 if ($definitions->{$field}->{type}) {
1774 $action="change $field"
1778 # if it's a primary key, drop the previous pk, before altering the table
1779 print " alter or create $field in $table\n" unless $silent;
1781 if ($key ne 'PRIMARY KEY') {
1782 # warn "alter table $table $action $field $type $null $key $extra default $default $after";
1783 $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1785 # warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1786 # something strange : for indexes UNIQUE, they are reported as primary key here.
1787 # but if you try to run with drop primary key, it fails.
1788 # thus, we run the query twice, one will fail, one will succeed.
1790 $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1791 $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1798 print "removing some unused data...\n";
1799 foreach my $table ( keys %linetodelete ) {
1800 foreach my $where ( @{linetodelete{$table}} ){
1801 print "DELETE FROM ".$table." where ".$where;
1803 my $sth = $dbh->prepare("DELETE FROM $table where $where");
1806 print "Error : $sth->errstr \n";
1811 # Populate tables with required data
1813 # synch table and deletedtable.
1814 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1815 my %deletedborrowers;
1816 print "synch'ing $table and deleted$table\n";
1817 $sth = $dbh->prepare("show columns from deleted$table");
1819 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1820 $deletedborrowers{$column}=1;
1822 $sth = $dbh->prepare("show columns from $table");
1825 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1826 unless ($deletedborrowers{$column}) {
1827 my $newcol="alter table deleted$table add $column $type";
1828 if ($null eq 'YES') {
1829 $newcol .= " NULL ";
1831 $newcol .= " NOT NULL ";
1833 $newcol .= "default ".$dbh->quote($default) if $default;
1834 $newcol .= " after $previous" if $previous;
1836 print "creating column $column\n";
1842 # update publisheddate
1844 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1846 my ($emptypublished) = $sth->fetchrow;
1847 if ($emptypublished) {
1848 print "Updating publisheddate\n";
1849 $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1851 foreach my $table ( keys %tabledata ) {
1852 print "Checking for data required in table $table...\n" unless $silent;
1853 my $tablerows = $tabledata{$table};
1854 foreach my $row (@$tablerows) {
1855 my $uniquefieldrequired = $row->{uniquefieldrequired};
1856 my $uniquevalue = $row->{$uniquefieldrequired};
1857 my $forceupdate = $row->{forceupdate};
1860 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1862 $sth->execute($uniquevalue);
1864 foreach my $field (keys %$forceupdate) {
1865 if ($forceupdate->{$field}) {
1866 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1867 $sth->execute($row->{$field}, $uniquevalue);
1871 print "Adding row to $table: " unless $silent;
1875 foreach my $field ( keys %$row ) {
1876 next if $field eq 'uniquefieldrequired';
1877 next if $field eq 'forceupdate';
1878 my $value = $row->{$field};
1879 push @values, $value;
1880 print " $field => $value" unless $silent;
1881 $fieldlist .= "$field,";
1882 $placeholders .= "?,";
1884 print "\n" unless $silent;
1885 $fieldlist =~ s/,$//;
1886 $placeholders =~ s/,$//;
1887 print "insert into $table ($fieldlist) values ($placeholders)";
1890 "insert into $table ($fieldlist) values ($placeholders)");
1891 $sth->execute(@values);
1897 # check indexes and create them when needed
1899 print "Checking for index required...\n" unless $silent;
1900 foreach my $table ( keys %indexes ) {
1902 # read all indexes from $table
1904 $sth = $dbh->prepare("show index from $table");
1906 my %existingindexes;
1907 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1908 $existingindexes{$key_name} = 1;
1910 # read indexes to check
1911 my $tablerows = $indexes{$table};
1912 foreach my $row (@$tablerows) {
1913 my $key_name=$row->{indexname};
1914 if ($existingindexes{$key_name} eq 1) {
1915 # print "$key_name existing";
1917 print "\tCreating index $key_name in $table\n";
1919 if ($row->{indexname} eq 'PRIMARY') {
1920 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1922 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1925 print "Error $sql : $dbh->err \n" if $dbh->err;
1931 # check foreign keys and create them when needed
1933 print "Checking for foreign keys required...\n" unless $silent;
1934 foreach my $table ( keys %foreign_keys ) {
1936 # read all indexes from $table
1938 $sth = $dbh->prepare("show table status like '$table'");
1940 my $stat = $sth->fetchrow_hashref;
1941 # read indexes to check
1942 my $tablerows = $foreign_keys{$table};
1943 foreach my $row (@$tablerows) {
1944 my $foreign_table=$row->{foreigntable};
1945 if ($stat->{'Comment'} =~/$foreign_table/) {
1946 # print "$foreign_table existing\n";
1948 print "\tCreating foreign key $foreign_table in $table\n";
1949 # first, drop any orphan value in child table
1950 if ($row->{onDelete} ne "RESTRICT") {
1951 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
1953 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
1955 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
1956 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
1957 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
1960 print "====================
1961 An error occured during :
1963 It probably means there is something wrong in your DB : a row ($table.$row->{key}) refers to a value in $row->{foreigntable}.$row->{foreignkey} that does not exist. solve the problem and run updater again (or just the previous SQL statement).
1964 You can find those values with select
1965 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
1966 ====================\n
1972 # now drop useless tables
1973 foreach $table ( @TableToDelete ) {
1974 if ( $existingtables{$table} ) {
1975 print "Dropping unused table $table\n" if $debug and not $silent;
1976 $dbh->do("drop table $table");
1978 print "Error : $dbh->errstr \n";
1987 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
1990 # 1st, get how many biblio we will have to do...
1991 $sth = $dbh->prepare('select count(*) from marc_biblio');
1993 my ($totaltodo) = $sth->fetchrow;
1995 $sth = $dbh->prepare("show columns from biblio");
1998 my $bibliofwexist=0;
1999 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
2000 $bibliofwexist=1 if $column eq 'frameworkcode';
2002 unless ($bibliofwexist) {
2003 print "moving biblioframework to biblio table\n";
2004 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
2005 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
2007 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
2009 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
2010 $sth_update->execute($frameworkcode,$biblionumber);
2012 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
2017 # at last, remove useless fields
2018 foreach $table ( keys %uselessfields ) {
2019 my @fields = split /,/,$uselessfields{$table};
2022 foreach my $fieldtodrop (@fields) {
2023 $fieldtodrop =~ s/\t//g;
2024 $fieldtodrop =~ s/\n//g;
2026 $sth = $dbh->prepare("show columns from $table");
2028 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
2030 $exists =1 if ($column eq $fieldtodrop);
2033 print "deleting $fieldtodrop field in $table...\n" unless $silent;
2034 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
2041 # Changing aqbookfund's primary key
2043 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2051 # Revision 1.170 2007/06/26 13:25:37 tipaul
2052 # removing some useless tables from updatedatabase
2054 # Revision 1.169 2007/06/26 09:23:26 tipaul
2055 # improving OpacBrowser systempref explanation
2057 # Revision 1.168 2007/06/25 15:02:31 tipaul
2058 # missing field declaration
2060 # Revision 1.167 2007/06/15 13:09:08 toins
2061 # bugfix : bibliotitems.dewey & deletedbiblioitems.dewey mustn't be double(8,6).
2063 # Revision 1.166 2007/06/08 09:40:12 toins
2064 # bug fix : items.homebranch must be VARCHAR(10)
2066 # Revision 1.165 2007/05/23 16:33:10 tipaul
2067 # skip move to innoDB for the 4 22 tables, that are used to store MARC records, are useless in Koha 3.0 The process is very very long, so the updatedatabase should speed up a lot (by long I mean 1 hour on my Dual core with SCSI disk, for a 50 000 biblios long table
2069 # Revision 1.164 2007/05/04 16:24:09 tipaul
2070 # various bugfixes on parameters modules + adding default NoZebraIndexes systempreference if it's empty
2072 # Revision 1.163 2007/05/02 16:44:31 tipaul
2073 # NoZebra SQL index management :
2074 # * adding 3 subs in Biblio.pm
2075 # - GetNoZebraIndexes, that get the index structure in a new systempreference (added with this commit)
2076 # - _DelBiblioNoZebra, that retrieve all index entries for a biblio and remove in a variable the biblio reference
2077 # - _AddBiblioNoZebra, that add index entries for a biblio.
2078 # Note that the 2 _Add and _Del subs work only in a hash variable, to speed up things in case of a modif (ie : delete+add). The effective SQL update is done in the ModZebra sub (that existed before, and dealed with zebra index).
2079 # I think the code has to be more deeply tested, but it works at least partially.
2081 # Revision 1.162 2007/04/30 16:16:50 tipaul
2082 # bugfix for updatedatabase : when there is no default value (NULL fields) + removing bibliothesaurus table+adding NoZebra systempref (False by default)
2084 # Revision 1.161 2007/04/13 16:27:55 hdl
2085 # Adding Version variable to systempreferences.
2087 # Revision 1.160 2007/03/19 18:35:13 toins
2088 # - adding default value in marc_subfield_structure.
2089 # - now marc_subfields_structure displays subfields in tab view.
2091 # Revision 1.159 2007/03/16 01:25:09 kados
2092 # Using my precrash CVS copy I did the following:
2094 # cvs -z3 -d:ext:kados@cvs.savannah.nongnu.org:/sources/koha co -P koha
2095 # find koha.precrash -type d -name "CVS" -exec rm -v {} \;
2096 # cp -r koha.precrash/* koha/
2100 # This should in theory put us right back where we were before the crash
2102 # Revision 1.159 2007/03/12 17:52:30 rych
2103 # add pri key to userflags
2105 # Revision 1.158 2007/03/09 15:14:57 tipaul
2106 # rel_3_0 moved to HEAD
2108 # Revision 1.157.2.56 2007/01/31 16:22:54 btoumi
2109 # -add possibility to use isbn with length of 13 characters
2110 # for Import datas in the reservoir.
2111 # -modify isbn field in marc_breeding table (varchar 13)
2112 # -add isbn filter (no - )when u read a notice from reservoir
2113 # -add filter to have right field 100
2115 # Revision 1.157.2.55 2007/01/30 10:50:19 tipaul
2116 # adding 2 usefull indexes to biblioitems table
2118 # Revision 1.157.2.54 2007/01/29 16:45:52 toins
2119 # * adding a new default authorised value : SUGGEST.
2120 # SUGGEST give some reasons to accept or reject a suggestion.
2122 # * default value for borrowersMandatoryfield syspref is now "cardnumber|surname|adress"
2124 # Revision 1.157.2.53 2007/01/26 20:48:37 hdl
2125 # Serials management : Bugfixes + improvements.
2126 # - Partial dates are now managed
2127 # - next Date Calculation with irregularity tested for 1 week and 1 month.
2128 # - manage if subscription is abouttoexpire or expired.
2129 # - Adding some information on serials pages about subscription.
2130 # - Managing irregularity with numbers.
2131 # - Adding Internal Notes in subscription management.
2132 # - Repeating Button above pages.
2134 # Please run Updatedatabase to change irregularity and add internalnotes field to subscription
2136 # Revision 1.157.2.52 2007/01/24 13:57:26 tipaul
2137 # - setting supplierid to auto_increment (HDL : could you check that is works, i'm not 100% sure)
2138 # - removing 22 -> 30 marc_subfield_table -> marcxml stuff, it's now in misc/migration_tools/22_to_30/
2140 # Revision 1.157.2.51 2007/01/18 09:58:45 tipaul
2141 # defaulting NOT NULL fields (to '')
2143 # Revision 1.157.2.50 2007/01/18 09:39:21 tipaul
2144 # issuedate must be defaulted with ' '
2146 # Revision 1.157.2.49 2007/01/18 09:37:30 tipaul
2147 # removing 2 field definitions that were here twice
2149 # Revision 1.157.2.48 2007/01/15 09:55:40 toins
2150 # adding a new logging systempref : FinesLog.
2152 # Revision 1.157.2.47 2007/01/12 18:09:49 toins
2155 # Revision 1.157.2.46 2007/01/11 14:35:39 tipaul
2156 # adding Opac Browser feature : the build_browser_and_cloud.pl script will :
2157 # - fill the browser table, that enable browsing, digit by digit of a given category, the catalogue. A complete dewey classification is provided in the script, active only for french libraries, of course (although, for instance, the script check that the catalogue is in english for developping convenience)
2158 # - fill the tags table, that contains the subject cloud.
2160 # The cloud part is a copy of the previous build_tags.pl script that can be deleted : those 2 scripts require to parse all the catalogue to extract interesting data, so they are long. It's useless to parse the catalogue twice !
2162 # The commit also add the systempreference to hide/show the OpacBrowse in database & in systempref management script.
2164 # IMPROVEMENTS to do :
2165 # - the script that builds the tables can be improved to update only last week biblios (at the price of a small error in value links, but it's not a problem).
2166 # - add, in parameters section, a place to edit browser descriptions. The build script has to be updated to to avoid deleting existing browser descriptions.
2168 # Revision 1.157.2.45 2007/01/10 16:52:52 toins
2169 # Value for Log Features syspref are set to 0 by default.
2171 # Revision 1.157.2.44 2007/01/10 16:31:15 toins
2172 # new systems preferences :
2173 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
2174 # - BorrowersLog ( idem for borrowers )
2175 # - IssueLog (log all issue if set to 1)
2176 # - ReturnLog (log all return if set to 1)
2177 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
2179 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
2181 # Revision 1.157.2.43 2007/01/10 14:13:17 toins
2182 # opac_news.displayed is replaced by opac_news.number.
2183 # This field say how are ordered the news on the template.
2185 # Revision 1.157.2.42 2007/01/09 14:09:01 toins
2186 # 2 field added to opac_news.('expirationdate' and 'displayed').