road to 3.0 : updating a biblio in zebra seems to work. Still working on it, there...
[koha.git] / C4 / Biblio.pm
1 package C4::Biblio;
2
3 # Copyright 2000-2002 Katipo Communications
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 with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 use strict;
21 require Exporter;
22 use C4::Context;
23 use C4::Database;
24 use C4::Date;
25 use MARC::Record;
26 use MARC::File::USMARC;
27 use MARC::File::XML;
28
29 use vars qw($VERSION @ISA @EXPORT);
30
31 # set the version for version checking
32 $VERSION = 0.01;
33
34 @ISA = qw(Exporter);
35
36 #
37 # don't forget MARCxxx subs are exported only for testing purposes. Should not be used
38 # as the old-style API and the NEW one are the only public functions.
39 #
40 @EXPORT = qw(
41   &newbiblio &newbiblioitem
42   &newsubject &newsubtitle &newitems 
43   
44   &modbiblio &checkitems &modbibitem
45   &modsubtitle &modsubject &modaddauthor &moditem
46   
47   &delitem &deletebiblioitem &delbiblio
48   
49   &getbiblio &bibdata &bibitems &bibitemdata 
50   &barcodes &ItemInfo &itemdata &itemissues &itemcount 
51   &getsubject &getaddauthor &getsubtitle
52   &getwebbiblioitems &getwebsites
53   &getbiblioitembybiblionumber
54   &getbiblioitem &getitemsbybiblioitem
55
56   &MARCfind_marc_from_kohafield
57   &MARCfind_frameworkcode
58   &find_biblioitemnumber
59   &MARCgettagslib
60
61   &NEWnewbiblio &NEWnewitem
62   &NEWmodbiblio &NEWmoditem
63   &NEWdelbiblio &NEWdelitem
64   &NEWmodbiblioframework
65
66   &MARCkoha2marcBiblio &MARCmarc2koha
67   &MARCkoha2marcItem &MARChtml2marc
68   &MARCgetbiblio &MARCgetitem
69   &XMLgetbiblio
70   &char_decode
71   
72   &FindDuplicate
73   &DisplayISBN
74 );
75
76 =head1 NAME
77
78 C4::Biblio - acquisition, catalog  management functions
79
80 =head1 SYNOPSIS
81
82 ( lot of changes for Koha 3.0)
83
84 Koha 1.2 and previous version used a specific API to manage biblios. This API uses old-DB style parameters.
85 They are based on a hash, and store data in biblio/biblioitems/items tables (plus additionalauthors, bibliosubject and bibliosubtitle where applicable)
86
87 In Koha 2.0, we introduced a MARC-DB.
88
89 In Koha 3.0 we removed this MARC-DB for search as we wanted to use Zebra as search system.
90
91 So in Koha 3.0, saving a record means :
92  - storing the raw marc record (iso2709) in biblioitems.marc field. It contains both biblio & items informations.
93  - storing the "decoded information" in biblio/biblioitems/items as previously.
94  - using zebra to manage search & indexing on the MARC datas.
95  
96  In Koha, there is a systempreference saying "MARC=ON" or "MARC=OFF"
97  
98  * MARC=ON : when MARC=ON, koha uses a MARC::Record object (in sub parameters). Saving informations in the DB means : 
99  - transform the MARC record into a hash
100  - add the raw marc record into the hash
101  - store them & update zebra
102  
103  * MARC=OFF : when MARC=OFF, koha uses a hash object (in sub parameters). Saving informations in the DB means :
104  - transform the hash into a MARC record
105  - add the raw marc record into the hash
106  - store them and update zebra
107  
108  
109 That's why we need 3 types of subs :
110
111 =head2 REALxxx subs
112
113 all I<subs beginning by REAL> does effective storage of information (with a hash, one field of the hash being the raw marc record). Those subs also update the record in zebra. REAL subs should be only for internal use (called by NEW or "something else" subs
114
115 =head2 NEWxxx related subs
116
117 =over 4
118
119 all I<subs beginning by NEW> use MARC::Record as parameters. it's the API that MUST be used in MARC acquisition system. They just create the hash, add it the raw marc record. Then, they call REALxxx sub.
120
121 all subs requires/use $dbh as 1st parameter and a MARC::Record object as 2nd parameter. they sometimes requires another parameter.
122
123 =back
124
125 =head2 something_elsexxx related subs
126
127 =over 4
128
129 all I<subs beginning by seomething else> are the old-style API. They use a hash as parameter, transform the hash into a -small- marc record, and calls REAL subs.
130
131 all subs requires/use $dbh as 1st parameter and a hash as 2nd parameter.
132
133 =back
134
135 =head1 API
136
137 =cut
138
139 sub zebra_create {
140         my ($biblionumber,$record) = @_;
141         # create the iso2709 file for zebra
142 #       my $cgidir = C4::Context->intranetdir ."/cgi-bin";
143 #       unless (opendir(DIR, "$cgidir")) {
144 #                       $cgidir = C4::Context->intranetdir."/";
145 #       } 
146 #       closedir DIR;
147 #       my $filename = $cgidir."/zebra/biblios/BIBLIO".$biblionumber."iso2709";
148 #       open F,"> $filename";
149 #       print F $record->as_usmarc();
150 #       close F;
151 #       my $res = system("cd $cgidir/zebra;/usr/local/bin/zebraidx update biblios");
152 #       unlink($filename);
153         warn "zebra_create : $biblionumber =".$record->as_formatted;
154         eval {
155                 $Zconn = new ZOOM::Connection(C4::Context->config("zebradb"));
156         };
157         $Zconn->option(cqlfile => C4::Context->config("intranetdir")."/zebra/pqf.properties");
158 #       my $record = XMLgetbiblio($dbh,$biblionumber);
159         my $Zpackage = $Zconn->package();
160         $Zpackage->option(action => "specialUpdate");
161         $Zpackage->option(record => $record->as_xml());
162         $Zpackage->send("update");
163 }
164
165 =head2 @tagslib = &MARCgettagslib($dbh,1|0,$frameworkcode);
166
167 =over 4
168
169 2nd param is 1 for liblibrarian and 0 for libopac
170 $frameworkcode contains the framework reference. If empty or does not exist, the default one is used
171
172 returns a hash with all values for all fields and subfields for a given MARC framework :
173         $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
174                     ->{tab}        = "";            # XXX
175                     ->{mandatory}  = $mandatory;
176                     ->{repeatable} = $repeatable;
177                     ->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
178                                  ->{tab}              = $tab;
179                                  ->{mandatory}        = $mandatory;
180                                  ->{repeatable}       = $repeatable;
181                                  ->{authorised_value} = $authorised_value;
182                                  ->{authtypecode}     = $authtypecode;
183                                  ->{value_builder}    = $value_builder;
184                                  ->{kohafield}        = $kohafield;
185                                  ->{seealso}          = $seealso;
186                                  ->{hidden}           = $hidden;
187                                  ->{isurl}            = $isurl;
188                                  ->{link}            = $link;
189
190 =back
191
192 =cut
193
194 sub MARCgettagslib {
195     my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
196     $frameworkcode = "" unless $frameworkcode;
197     $forlibrarian = 1 unless $forlibrarian;
198     my $sth;
199     my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
200
201     # check that framework exists
202     $sth =
203       $dbh->prepare(
204         "select count(*) from marc_tag_structure where frameworkcode=?");
205     $sth->execute($frameworkcode);
206     my ($total) = $sth->fetchrow;
207     $frameworkcode = "" unless ( $total > 0 );
208     $sth =
209       $dbh->prepare(
210 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
211     );
212     $sth->execute($frameworkcode);
213     my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
214
215     while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
216         $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
217         $res->{$tag}->{tab}        = "";            # XXX
218         $res->{$tag}->{mandatory}  = $mandatory;
219         $res->{$tag}->{repeatable} = $repeatable;
220     }
221
222     $sth =
223       $dbh->prepare(
224 "select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link from marc_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
225     );
226     $sth->execute($frameworkcode);
227
228     my $subfield;
229     my $authorised_value;
230     my $authtypecode;
231     my $value_builder;
232     my $kohafield;
233     my $seealso;
234     my $hidden;
235     my $isurl;
236         my $link;
237
238     while (
239         ( $tag,         $subfield,   $liblibrarian,   , $libopac,      $tab,
240         $mandatory,     $repeatable, $authorised_value, $authtypecode,
241         $value_builder, $kohafield,  $seealso,          $hidden,
242         $isurl,                 $link )
243         = $sth->fetchrow
244       )
245     {
246         $res->{$tag}->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
247         $res->{$tag}->{$subfield}->{tab}              = $tab;
248         $res->{$tag}->{$subfield}->{mandatory}        = $mandatory;
249         $res->{$tag}->{$subfield}->{repeatable}       = $repeatable;
250         $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
251         $res->{$tag}->{$subfield}->{authtypecode}     = $authtypecode;
252         $res->{$tag}->{$subfield}->{value_builder}    = $value_builder;
253         $res->{$tag}->{$subfield}->{kohafield}        = $kohafield;
254         $res->{$tag}->{$subfield}->{seealso}          = $seealso;
255         $res->{$tag}->{$subfield}->{hidden}           = $hidden;
256         $res->{$tag}->{$subfield}->{isurl}            = $isurl;
257         $res->{$tag}->{$subfield}->{link}            = $link;
258     }
259     return $res;
260 }
261
262 =head2 ($tagfield,$tagsubfield) = &MARCfind_marc_from_kohafield($dbh,$kohafield);
263
264 =over 4
265
266 finds MARC tag and subfield for a given kohafield
267 kohafield is "table.field" where table= biblio|biblioitems|items, and field a field of the previous table
268
269 =back
270
271 =cut
272
273 sub MARCfind_marc_from_kohafield {
274     my ( $dbh, $kohafield,$frameworkcode ) = @_;
275     return 0, 0 unless $kohafield;
276     $frameworkcode='' unless $frameworkcode;
277         my $relations = C4::Context->marcfromkohafield;
278         return ($relations->{$frameworkcode}->{$kohafield}->[0],$relations->{$frameworkcode}->{$kohafield}->[1]);
279 }
280
281 =head2 $MARCRecord = &MARCgetbiblio($dbh,$biblionumber);
282
283 =over 4
284
285 Returns a MARC::Record for the biblio $biblionumber.
286
287 =cut
288
289 sub MARCgetbiblio {
290
291     # Returns MARC::Record of the biblio passed in parameter.
292     my ( $dbh, $biblionumber ) = @_;
293         my $sth = $dbh->prepare('select marc from biblioitems where biblionumber=?');
294         $sth->execute($biblionumber);
295         my ($marc) = $sth->fetchrow;
296         my $record = MARC::Record::new_from_usmarc($marc);
297     return $record;
298 }
299
300 =head2 $XML = &XMLgetbiblio($dbh,$biblionumber);
301
302 =over 4
303
304 Returns a raw XML for the biblio $biblionumber.
305
306 =cut
307
308 sub XMLgetbiblio {
309
310     # Returns MARC::Record of the biblio passed in parameter.
311     my ( $dbh, $biblionumber ) = @_;
312         my $sth = $dbh->prepare('select marcxml,marc from biblioitems where biblionumber=?');
313         $sth->execute($biblionumber);
314         my ($XML,$marc) = $sth->fetchrow;
315 #       my $record =MARC::Record::new_from_usmarc($marc);
316 #       warn "MARC : \n*-************************\n".$record->as_xml."\n*-************************\n";
317     return $XML;
318 }
319
320 =head2 $MARCrecord = &MARCgetitem($dbh,$biblionumber);
321
322 =over 4
323
324 Returns a MARC::Record with all items of biblio # $biblionumber
325
326 =back
327
328 =cut
329
330 sub MARCgetitem {
331
332     my ( $dbh, $biblionumber, $itemnumber ) = @_;
333         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
334         # get the complete MARC record
335         my $sth = $dbh->prepare("select marc from biblioitems where biblionumber=?");
336         $sth->execute($biblionumber);
337         my ($rawmarc) = $sth->fetchrow;
338         my $record = MARC::File::USMARC::decode($rawmarc);
339         # now, find the relevant itemnumber
340         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
341         # prepare the new item record
342         my $itemrecord = MARC::Record->new();
343         # parse all fields fields from the complete record
344         foreach ($record->field($itemnumberfield)) {
345                 # when the item field is found, save it
346                 if ($_->subfield($itemnumbersubfield) == $itemnumber) {
347                         $itemrecord->append_fields($_);
348                 }
349         }
350
351     return $itemrecord;
352 }
353
354 =head2 sub find_biblioitemnumber($dbh,$biblionumber);
355
356 =over 4
357
358 Returns the 1st biblioitemnumber related to $biblionumber. When MARC=ON we should have 1 biblionumber = 1 and only 1 biblioitemnumber
359 This sub is useless when MARC=OFF
360
361 =back
362
363 =cut
364 sub find_biblioitemnumber {
365         my ( $dbh, $biblionumber ) = @_;
366         my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
367         $sth->execute($biblionumber);
368         my ($biblioitemnumber) = $sth->fetchrow;
369         return $biblioitemnumber;
370 }
371
372 =head2 $frameworkcode = MARCfind_frameworkcode($dbh,$biblionumber);
373
374 =over 4
375
376 returns the framework of a given biblio
377
378 =back
379
380 =cut
381
382 sub MARCfind_frameworkcode {
383         my ( $dbh, $biblionumber ) = @_;
384         my $sth = $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
385         $sth->execute($biblionumber);
386         my ($frameworkcode) = $sth->fetchrow;
387         return $frameworkcode;
388 }
389
390 =head2 $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibliohash);
391
392 =over 4
393
394 MARCkoha2marcBiblio is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB biblio/biblioitem :
395 all entries of the hash are transformed into their matching MARC field/subfield.
396
397 =back
398
399 =cut
400
401 sub MARCkoha2marcBiblio {
402
403         # this function builds partial MARC::Record from the old koha-DB fields
404         my ( $dbh, $bibliohash ) = @_;
405         # we don't have biblio entries in the hash, so we add them first
406         my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
407         $sth->execute($bibliohash->{biblionumber});
408         my $biblio = $sth->fetchrow_hashref;
409         foreach (keys %$biblio) {
410                 $bibliohash->{$_}=$biblio->{$_};
411         }
412         $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
413         my $record = MARC::Record->new();
414         foreach ( keys %$bibliohash ) {
415                 &MARCkoha2marcOnefield( $sth, $record, "biblio." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
416                 &MARCkoha2marcOnefield( $sth, $record, "biblioitems." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
417         }
418
419         # other fields => additional authors, subjects, subtitles
420         my $sth2 = $dbh->prepare(" SELECT author FROM additionalauthors WHERE biblionumber=?");
421         $sth2->execute($bibliohash->{biblionumber});
422         while ( my $row = $sth2->fetchrow_hashref ) {
423                 &MARCkoha2marcOnefield( $sth, $record, "additionalauthors.author", $bibliohash->{'author'},'' );
424         }
425         $sth2 = $dbh->prepare(" SELECT subject FROM bibliosubject WHERE biblionumber=?");
426         $sth2->execute($bibliohash->{biblionumber});
427         while ( my $row = $sth2->fetchrow_hashref ) {
428                 &MARCkoha2marcOnefield( $sth, $record, "bibliosubject.subject", $row->{'subject'},'' );
429         }
430         $sth2 = $dbh->prepare(" SELECT subtitle FROM bibliosubtitle WHERE biblionumber=?");
431         $sth2->execute($bibliohash->{biblionumber});
432         while ( my $row = $sth2->fetchrow_hashref ) {
433                 &MARCkoha2marcOnefield( $sth, $record, "bibliosubtitle.subtitle", $row->{'subtitle'},'' );
434         }
435         
436         return $record;
437 }
438
439 =head2 $MARCRecord = &MARCkoha2marcItem($dbh,$biblionumber,itemnumber);
440
441 MARCkoha2marcItem is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB items :
442 all entries of the hash are transformed into their matching MARC field/subfield.
443
444 =over 4
445
446 =back
447
448 =cut
449
450 sub MARCkoha2marcItem {
451
452     # this function builds partial MARC::Record from the old koha-DB fields
453     my ( $dbh, $item ) = @_;
454
455     #    my $dbh=&C4Connect;
456     my $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
457     my $record = MARC::Record->new();
458
459         foreach( keys %$item ) {
460                 if ( $item->{$_} ) {
461                         &MARCkoha2marcOnefield( $sth, $record, "items." . $_,
462                                 $item->{$_},'' );
463                 }
464         }
465     return $record;
466 }
467
468 =head2 MARCkoha2marcOnefield
469
470 =over 4
471
472 This sub is for internal use only, used by koha2marcBiblio & koha2marcItem
473
474 =back
475
476 =cut
477
478 sub MARCkoha2marcOnefield {
479     my ( $sth, $record, $kohafieldname, $value,$frameworkcode ) = @_;
480     my $tagfield;
481     my $tagsubfield;
482     $sth->execute($frameworkcode,$kohafieldname);
483     if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
484         if ( $record->field($tagfield) ) {
485             my $tag = $record->field($tagfield);
486             if ($tag) {
487                 $tag->add_subfields( $tagsubfield, $value );
488                 $record->delete_field($tag);
489                 $record->add_fields($tag);
490             }
491         }
492         else {
493             $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
494         }
495     }
496     return $record;
497 }
498
499 =head2 $MARCrecord = MARChtml2marc($dbh,$rtags,$rsubfields,$rvalues,%indicators);
500
501 =over 4
502
503 transforms the parameters (coming from HTML form) into a MARC::Record
504 parameters with r are references to arrays.
505
506 FIXME : should be improved for 3.0, to avoid having 4 differents arrays
507
508 =back
509
510 =cut
511
512 sub MARChtml2marc {
513         my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
514         my $prevtag = -1;
515         my $record = MARC::Record->new();
516 #       my %subfieldlist=();
517         my $prevvalue; # if tag <10
518         my $field; # if tag >=10
519         for (my $i=0; $i< @$rtags; $i++) {
520                 next unless @$rvalues[$i];
521                 # rebuild MARC::Record
522 #                       warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
523                 if (@$rtags[$i] ne $prevtag) {
524                         if ($prevtag < 10) {
525                                 if ($prevvalue) {
526                                         if ($prevtag ne '000') {
527                                                 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
528                                         } else {
529                                                 $record->leader($prevvalue);
530                                         }
531                                 }
532                         } else {
533                                 if ($field) {
534                                         $record->add_fields($field);
535                                 }
536                         }
537                         $indicators{@$rtags[$i]}.='  ';
538                         if (@$rtags[$i] <10) {
539                                 $prevvalue= @$rvalues[$i];
540                                 undef $field;
541                         } else {
542                                 undef $prevvalue;
543                                 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
544 #                       warn "1=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
545                         }
546                         $prevtag = @$rtags[$i];
547                 } else {
548                         if (@$rtags[$i] <10) {
549                                 $prevvalue=@$rvalues[$i];
550                         } else {
551                                 if (length(@$rvalues[$i])>0) {
552                                         $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
553 #                       warn "2=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
554                                 }
555                         }
556                         $prevtag= @$rtags[$i];
557                 }
558         }
559         # the last has not been included inside the loop... do it now !
560         $record->add_fields($field) if $field;
561 #       warn "HTML2MARC=".$record->as_formatted;
562         return $record;
563 }
564
565
566 =head2 $hash = &MARCmarc2koha($dbh,$MARCRecord);
567
568 =over 4
569
570 builds a hash with old-db datas from a MARC::Record
571
572 =back
573
574 =cut
575
576 sub MARCmarc2koha {
577         my ($dbh,$record,$frameworkcode) = @_;
578         my $sth=$dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
579         my $result;
580         my $sth2=$dbh->prepare("SHOW COLUMNS from biblio");
581         $sth2->execute;
582         my $field;
583         while (($field)=$sth2->fetchrow) {
584 #               warn "biblio.".$field;
585                 $result=&MARCmarc2kohaOneField($sth,"biblio",$field,$record,$result,$frameworkcode);
586         }
587         $sth2=$dbh->prepare("SHOW COLUMNS from biblioitems");
588         $sth2->execute;
589         while (($field)=$sth2->fetchrow) {
590                 if ($field eq 'notes') { $field = 'bnotes'; }
591 #               warn "biblioitems".$field;
592                 $result=&MARCmarc2kohaOneField($sth,"biblioitems",$field,$record,$result,$frameworkcode);
593         }
594         $sth2=$dbh->prepare("SHOW COLUMNS from items");
595         $sth2->execute;
596         while (($field)=$sth2->fetchrow) {
597 #               warn "items".$field;
598                 $result=&MARCmarc2kohaOneField($sth,"items",$field,$record,$result,$frameworkcode);
599         }
600         # additional authors : specific
601         $result = &MARCmarc2kohaOneField($sth,"bibliosubtitle","subtitle",$record,$result,$frameworkcode);
602         $result = &MARCmarc2kohaOneField($sth,"additionalauthors","additionalauthors",$record,$result,$frameworkcode);
603 # modify copyrightdate to keep only the 1st year found
604         my $temp = $result->{'copyrightdate'};
605         if ($temp){
606                 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
607                 if ($1>0) {
608                         $result->{'copyrightdate'} = $1;
609                 } else { # if no cYYYY, get the 1st date.
610                         $temp =~ m/(\d\d\d\d)/;
611                         $result->{'copyrightdate'} = $1;
612                 }
613         }
614 # modify publicationyear to keep only the 1st year found
615         $temp = $result->{'publicationyear'};
616         $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
617         if ($1>0) {
618                 $result->{'publicationyear'} = $1;
619         } else { # if no cYYYY, get the 1st date.
620                 $temp =~ m/(\d\d\d\d)/;
621                 $result->{'publicationyear'} = $1;
622         }
623         return $result;
624 }
625
626 sub MARCmarc2kohaOneField {
627
628 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
629     my ( $sth, $kohatable, $kohafield, $record, $result,$frameworkcode ) = @_;
630     #    warn "kohatable / $kohafield / $result / ";
631     my $res = "";
632     my $tagfield;
633     my $subfield;
634     ( $tagfield, $subfield ) = MARCfind_marc_from_kohafield("",$kohatable.".".$kohafield,$frameworkcode);
635     foreach my $field ( $record->field($tagfield) ) {
636                 if ($field->tag()<10) {
637                         if ($result->{$kohafield}) {
638                                 # Reverse array filled with elements from repeated subfields 
639                                 # from first to last to avoid last to first concatenation of 
640                                 # elements in Koha DB.  -- thd.
641                                 $result->{$kohafield} .= " | ".reverse($field->data());
642                         } else {
643                                 $result->{$kohafield} = $field->data();
644                         }
645                 } else {
646                         if ( $field->subfields ) {
647                                 my @subfields = $field->subfields();
648                                 foreach my $subfieldcount ( 0 .. $#subfields ) {
649                                         if ($subfields[$subfieldcount][0] eq $subfield) {
650                                                 if ( $result->{$kohafield} ) {
651                                                         $result->{$kohafield} .= " | " . $subfields[$subfieldcount][1];
652                                                 }
653                                                 else {
654                                                         $result->{$kohafield} = $subfields[$subfieldcount][1];
655                                                 }
656                                         }
657                                 }
658                         }
659                 }
660     }
661 #       warn "OneField for $kohatable.$kohafield and $frameworkcode=> $tagfield, $subfield";
662     return $result;
663 }
664
665 =head2 ($biblionumber,$biblioitemnumber) = NEWnewbibilio($dbh,$MARCRecord,$frameworkcode);
666
667 =over 4
668
669 creates a biblio from a MARC::Record.
670
671 =back
672
673 =cut
674
675 sub NEWnewbiblio {
676     my ( $dbh, $record, $frameworkcode ) = @_;
677     my $biblionumber;
678     my $biblioitemnumber;
679     my $olddata = MARCmarc2koha( $dbh, $record,$frameworkcode );
680         $olddata->{frameworkcode} = $frameworkcode;
681     $biblionumber = REALnewbiblio( $dbh, $olddata );
682         $olddata->{biblionumber} = $biblionumber;
683         # add biblionumber into the MARC record (it's the ID for zebra)
684         my ( $tagfield, $tagsubfield ) =
685                                         MARCfind_marc_from_kohafield( $dbh, "biblio.biblionumber",$frameworkcode );
686         # create the field
687         my $newfield;
688         if ($tagfield<10) {
689                 $newfield = MARC::Field->new(
690                         $tagfield, $biblionumber,
691                 );
692         } else {
693                 $newfield = MARC::Field->new(
694                         $tagfield, '', '', "$tagsubfield" => $biblionumber,
695                 );
696         }
697         # drop old field (just in case it already exist and create new one...
698         my $old_field = $record->field($tagfield);
699         $record->delete_field($old_field);
700         $record->add_fields($newfield);
701
702         #create the marc entry, that stores the rax marc record in Koha 3.0
703         $olddata->{marc} = $record->as_usmarc();
704         $olddata->{marcxml} = $record->as_xml();
705         # and create biblioitem, that's all folks !
706     $biblioitemnumber = REALnewbiblioitem( $dbh, $olddata );
707
708     # search subtiles, addiauthors and subjects
709     ( $tagfield, $tagsubfield ) =
710       MARCfind_marc_from_kohafield( $dbh, "additionalauthors.author",$frameworkcode );
711     my @addiauthfields = $record->field($tagfield);
712     foreach my $addiauthfield (@addiauthfields) {
713         my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
714         foreach my $subfieldcount ( 0 .. $#addiauthsubfields ) {
715             REALmodaddauthor( $dbh, $biblionumber,
716                 $addiauthsubfields[$subfieldcount] );
717         }
718     }
719     ( $tagfield, $tagsubfield ) =
720       MARCfind_marc_from_kohafield( $dbh, "bibliosubtitle.subtitle",$frameworkcode );
721     my @subtitlefields = $record->field($tagfield);
722     foreach my $subtitlefield (@subtitlefields) {
723         my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
724         foreach my $subfieldcount ( 0 .. $#subtitlesubfields ) {
725             REALnewsubtitle( $dbh, $biblionumber,
726                 $subtitlesubfields[$subfieldcount] );
727         }
728     }
729     ( $tagfield, $tagsubfield ) =
730       MARCfind_marc_from_kohafield( $dbh, "bibliosubject.subject",$frameworkcode );
731     my @subj = $record->field($tagfield);
732     my @subjects;
733     foreach my $subject (@subj) {
734         my @subjsubfield = $subject->subfield($tagsubfield);
735         foreach my $subfieldcount ( 0 .. $#subjsubfield ) {
736             push @subjects, $subjsubfield[$subfieldcount];
737         }
738     }
739     REALmodsubject( $dbh, $biblionumber, 1, @subjects );
740     return ( $biblionumber, $biblioitemnumber );
741 }
742
743 =head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
744
745 =over 4
746
747 modify the framework of a biblio
748
749 =back
750
751 =cut
752
753 sub NEWmodbiblioframework {
754         my ($dbh,$biblionumber,$frameworkcode) =@_;
755         my $sth = $dbh->prepare("Update biblio SET frameworkcode=? WHERE biblionumber=?");
756         $sth->execute($frameworkcode,$biblionumber);
757         return 1;
758 }
759
760 =head2 NEWmodbiblio($dbh,$MARCrecord,$biblionumber,$frameworkcode);
761
762 =over 4
763
764 modify a biblio (MARC=ON)
765
766 =back
767
768 =cut
769
770 sub NEWmodbiblio {
771         my ($dbh,$record,$biblionumber,$frameworkcode) =@_;
772         $frameworkcode="" unless $frameworkcode;
773 #       &MARCmodbiblio($dbh,$bibid,$record,$frameworkcode,0);
774         my $oldbiblio = MARCmarc2koha($dbh,$record,$frameworkcode);
775         
776         $oldbiblio->{frameworkcode} = $frameworkcode;
777         #create the marc entry, that stores the rax marc record in Koha 3.0
778         $oldbiblio->{biblionumber} = $biblionumber unless $oldbiblio->{biblionumber};
779         $oldbiblio->{marc} = $record->as_usmarc();
780         $oldbiblio->{marcxml} = $record->as_xml();
781         warn "dans NEWmodbiblio $biblionumber = ".$oldbiblio->{biblionumber}." = ".$oldbiblio->{marcxml};
782         REALmodbiblio($dbh,$oldbiblio);
783         REALmodbiblioitem($dbh,$oldbiblio);
784         # now, modify addi authors, subject, addititles.
785         my ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"additionalauthors.author",$frameworkcode);
786         my @addiauthfields = $record->field($tagfield);
787         foreach my $addiauthfield (@addiauthfields) {
788                 my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
789                 $dbh->do("delete from additionalauthors where biblionumber=$biblionumber");
790                 foreach my $subfieldcount (0..$#addiauthsubfields) {
791                         REALmodaddauthor($dbh,$biblionumber,$addiauthsubfields[$subfieldcount]);
792                 }
793         }
794         ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubtitle.subtitle",$frameworkcode);
795         my @subtitlefields = $record->field($tagfield);
796         foreach my $subtitlefield (@subtitlefields) {
797                 my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
798                 # delete & create subtitle again because REALmodsubtitle can't handle new subtitles
799                 # between 2 modifs
800                 $dbh->do("delete from bibliosubtitle where biblionumber=$biblionumber");
801                 foreach my $subfieldcount (0..$#subtitlesubfields) {
802                         foreach my $subtit(split /\||#/,$subtitlesubfields[$subfieldcount]) {
803                                 REALnewsubtitle($dbh,$biblionumber,$subtit);
804                         }
805                 }
806         }
807         ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubject.subject",$frameworkcode);
808         my @subj = $record->field($tagfield);
809         my @subjects;
810         foreach my $subject (@subj) {
811                 my @subjsubfield = $subject->subfield($tagsubfield);
812                 foreach my $subfieldcount (0..$#subjsubfield) {
813                         push @subjects,$subjsubfield[$subfieldcount];
814                 }
815         }
816         REALmodsubject($dbh,$biblionumber,1,@subjects);
817         return 1;
818 }
819
820 =head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
821
822 =over 4
823
824 delete a biblio
825
826 =back
827
828 =cut
829
830 sub NEWdelbiblio {
831     my ( $dbh, $bibid ) = @_;
832     my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
833     &REALdelbiblio( $dbh, $biblio );
834     my $sth =
835       $dbh->prepare(
836         "select biblioitemnumber from biblioitems where biblionumber=?");
837     $sth->execute($biblio);
838     while ( my ($biblioitemnumber) = $sth->fetchrow ) {
839         REALdelbiblioitem( $dbh, $biblioitemnumber );
840     }
841     &MARCdelbiblio( $dbh, $bibid, 0 );
842 }
843
844 =head2 $itemnumber = NEWnewitem($dbh, $record, $biblionumber, $biblioitemnumber);
845
846 =over 4
847
848 creates an item from a MARC::Record
849
850 =back
851
852 =cut
853
854 sub NEWnewitem {
855     my ( $dbh, $record, $biblionumber, $biblioitemnumber ) = @_;
856
857     # add item in old-DB
858         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
859     my $item = &MARCmarc2koha( $dbh, $record,$frameworkcode );
860     # needs old biblionumber and biblioitemnumber
861     $item->{'biblionumber'} = $biblionumber;
862     $item->{'biblioitemnumber'}=$biblioitemnumber;
863         $item->{marc} = $record->as_usmarc();
864     my ( $itemnumber, $error ) = &REALnewitems( $dbh, $item, $item->{barcode} );
865         return $itemnumber;
866 }
867
868
869 =head2 $itemnumber = NEWmoditem($dbh, $record, $biblionumber, $biblioitemnumber,$itemnumber);
870
871 =over 4
872
873 Modify an item
874
875 =back
876
877 =cut
878
879 sub NEWmoditem {
880     my ( $dbh, $record, $biblionumber, $biblioitemnumber, $itemnumber) = @_;
881     
882         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
883     my $olditem = MARCmarc2koha( $dbh, $record,$frameworkcode );
884         # add MARC record
885         $olditem->{marc} = $record->as_usmarc();
886         $olditem->{biblionumber} = $biblionumber;
887         $olditem->{biblioitemnumber} = $biblioitemnumber;
888         # and modify item
889     REALmoditem( $dbh, $olditem );
890 }
891
892
893 =head2 $itemnumber = NEWdelitem($dbh, $biblionumber, $biblioitemnumber, $itemnumber);
894
895 =over 4
896
897 delete an item
898
899 =back
900
901 =cut
902
903 sub NEWdelitem {
904     my ( $dbh, $bibid, $itemnumber ) = @_;
905     my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
906     &REALdelitem( $dbh, $itemnumber );
907     &MARCdelitem( $dbh, $bibid, $itemnumber );
908 }
909
910
911 =head2 $biblionumber = REALnewbiblio($dbh,$biblio);
912
913 =over 4
914
915 adds a record in biblio table. Datas are in the hash $biblio.
916
917 =back
918
919 =cut
920
921 sub REALnewbiblio {
922     my ( $dbh, $biblio ) = @_;
923
924         $dbh->do('lock tables biblio WRITE');
925     my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
926     $sth->execute;
927     my $data   = $sth->fetchrow_arrayref;
928     my $bibnum = $$data[0] + 1;
929     my $series = 0;
930
931     if ( $biblio->{'seriestitle'} ) { $series = 1 }
932     $sth->finish;
933     $sth =
934       $dbh->prepare("insert into biblio set     biblionumber=?, title=?,                author=?,       copyrightdate=?,
935                                                                                         serial=?,               seriestitle=?,  notes=?,        abstract=?,
936                                                                                         unititle=?"
937     );
938     $sth->execute(
939         $bibnum,             $biblio->{'title'},
940         $biblio->{'author'}, $biblio->{'copyrightdate'},
941         $biblio->{'serial'},             $biblio->{'seriestitle'},
942         $biblio->{'notes'},  $biblio->{'abstract'},
943                 $biblio->{'unititle'}
944     );
945
946     $sth->finish;
947         $dbh->do('unlock tables');
948     return ($bibnum);
949 }
950
951 =head2 $biblionumber = REALmodbiblio($dbh,$biblio);
952
953 =over 4
954
955 modify a record in biblio table. Datas are in the hash $biblio.
956
957 =back
958
959 =cut
960
961 sub REALmodbiblio {
962     my ( $dbh, $biblio ) = @_;
963     my $sth = $dbh->prepare("Update biblio set  title=?,                author=?,       abstract=?,     copyrightdate=?,
964                                                                                                 seriestitle=?,  serial=?,       unititle=?,     notes=?,        frameworkcode=? 
965                                                                                         where biblionumber = ?"
966     );
967     $sth->execute(
968                 $biblio->{'title'},       $biblio->{'author'},
969                 $biblio->{'abstract'},    $biblio->{'copyrightdate'},
970                 $biblio->{'seriestitle'}, $biblio->{'serial'},
971                 $biblio->{'unititle'},    $biblio->{'notes'},
972                 $biblio->{frameworkcode},
973                 $biblio->{'biblionumber'}
974     );
975         $sth->finish;
976         return ( $biblio->{'biblionumber'} );
977 }    # sub modbiblio
978
979 =head2 REALmodsubtitle($dbh,$bibnum,$subtitle);
980
981 =over 4
982
983 modify subtitles in bibliosubtitle table.
984
985 =back
986
987 =cut
988
989 sub REALmodsubtitle {
990     my ( $dbh, $bibnum, $subtitle ) = @_;
991     my $sth =
992       $dbh->prepare(
993         "update bibliosubtitle set subtitle = ? where biblionumber = ?");
994     $sth->execute( $subtitle, $bibnum );
995     $sth->finish;
996 }    # sub modsubtitle
997
998 =head2 REALmodaddauthor($dbh,$bibnum,$author);
999
1000 =over 4
1001
1002 adds or modify additional authors
1003 NOTE :  Strange sub : seems to delete MANY and add only ONE author... maybe buggy ?
1004
1005 =back
1006
1007 =cut
1008
1009 sub REALmodaddauthor {
1010     my ( $dbh, $bibnum, @authors ) = @_;
1011
1012     #    my $dbh   = C4Connect;
1013     my $sth =
1014       $dbh->prepare("Delete from additionalauthors where biblionumber = ?");
1015
1016     $sth->execute($bibnum);
1017     $sth->finish;
1018     foreach my $author (@authors) {
1019         if ( $author ne '' ) {
1020             $sth =
1021               $dbh->prepare(
1022                 "Insert into additionalauthors set author = ?, biblionumber = ?"
1023             );
1024
1025             $sth->execute( $author, $bibnum );
1026
1027             $sth->finish;
1028         }    # if
1029     }
1030 }    # sub modaddauthor
1031
1032 =head2 $errors = REALmodsubject($dbh,$bibnum, $force, @subject);
1033
1034 =over 4
1035
1036 modify/adds subjects
1037
1038 =back
1039
1040 =cut
1041 sub REALmodsubject {
1042     my ( $dbh, $bibnum, $force, @subject ) = @_;
1043
1044     #  my $dbh   = C4Connect;
1045     my $count = @subject;
1046     my $error="";
1047     for ( my $i = 0 ; $i < $count ; $i++ ) {
1048         $subject[$i] =~ s/^ //g;
1049         $subject[$i] =~ s/ $//g;
1050         my $sth =
1051           $dbh->prepare(
1052 "select * from catalogueentry where entrytype = 's' and catalogueentry = ?"
1053         );
1054         $sth->execute( $subject[$i] );
1055
1056         if ( my $data = $sth->fetchrow_hashref ) {
1057         }
1058         else {
1059             if ( $force eq $subject[$i] || $force == 1 ) {
1060
1061                 # subject not in aut, chosen to force anway
1062                 # so insert into cataloguentry so its in auth file
1063                 my $sth2 =
1064                   $dbh->prepare(
1065 "Insert into catalogueentry (entrytype,catalogueentry) values ('s',?)"
1066                 );
1067
1068                 $sth2->execute( $subject[$i] ) if ( $subject[$i] );
1069                 $sth2->finish;
1070             }
1071             else {
1072                 $error =
1073                   "$subject[$i]\n does not exist in the subject authority file";
1074                 my $sth2 =
1075                   $dbh->prepare(
1076 "Select * from catalogueentry where entrytype = 's' and (catalogueentry like ? or catalogueentry like ? or catalogueentry like ?)"
1077                 );
1078                 $sth2->execute( "$subject[$i] %", "% $subject[$i] %",
1079                     "% $subject[$i]" );
1080                 while ( my $data = $sth2->fetchrow_hashref ) {
1081                     $error .= "<br>$data->{'catalogueentry'}";
1082                 }    # while
1083                 $sth2->finish;
1084             }    # else
1085         }    # else
1086         $sth->finish;
1087     }    # else
1088     if ($error eq '') {
1089         my $sth =
1090           $dbh->prepare("Delete from bibliosubject where biblionumber = ?");
1091         $sth->execute($bibnum);
1092         $sth->finish;
1093         $sth =
1094           $dbh->prepare(
1095             "Insert into bibliosubject (subject,biblionumber) values (?,?)");
1096         my $query;
1097         foreach $query (@subject) {
1098             $sth->execute( $query, $bibnum ) if ( $query && $bibnum );
1099         }    # foreach
1100         $sth->finish;
1101     }    # if
1102
1103     #  $dbh->disconnect;
1104     return ($error);
1105 }    # sub modsubject
1106
1107 =head2 REALmodbiblioitem($dbh, $biblioitem);
1108
1109 =over 4
1110
1111 modify a biblioitem
1112
1113 =back
1114
1115 =cut
1116 sub REALmodbiblioitem {
1117     my ( $dbh, $biblioitem ) = @_;
1118     my $query;
1119
1120     my $sth = $dbh->prepare("update biblioitems set number=?,volume=?,                  volumedate=?,           lccn=?,
1121                                                                                 itemtype=?,                     url=?,                          isbn=?,                         issn=?,
1122                                                                                 publishercode=?,        publicationyear=?,      classification=?,       dewey=?,
1123                                                                                 subclass=?,                     illus=?,                        pages=?,                        volumeddesc=?,
1124                                                                                 notes=?,                        size=?,                         place=?,                        marc=?,
1125                                                                                 marcxml=?
1126                                                         where biblioitemnumber=?");
1127         $sth->execute(  $biblioitem->{number},                  $biblioitem->{volume},  $biblioitem->{volumedate},      $biblioitem->{lccn},
1128                                         $biblioitem->{itemtype},                $biblioitem->{url},             $biblioitem->{isbn},    $biblioitem->{issn},
1129                                 $biblioitem->{publishercode},   $biblioitem->{publicationyear}, $biblioitem->{classification},  $biblioitem->{dewey},
1130                                 $biblioitem->{subclass},                $biblioitem->{illus},           $biblioitem->{pages},   $biblioitem->{volumeddesc},
1131                                 $biblioitem->{bnotes},                  $biblioitem->{size},            $biblioitem->{place},   $biblioitem->{marc},
1132                                         $biblioitem->{marcxml},                 $biblioitem->{biblioitemnumber});
1133         my $record = MARC::File::USMARC::decode($biblioitem->{marc});
1134         zebra_create($biblioitem->{biblionumber}, $record);
1135 #       warn "MOD : $biblioitem->{biblioitemnumber} = ".$biblioitem->{marc};
1136 }    # sub modbibitem
1137
1138 =head2 REALnewbiblioitem($dbh,$biblioitem);
1139
1140 =over 4
1141
1142 adds a biblioitem ($biblioitem is a hash with the values)
1143
1144 =back
1145
1146 =cut
1147
1148 sub REALnewbiblioitem {
1149         my ( $dbh, $biblioitem ) = @_;
1150
1151         $dbh->do("lock tables biblioitems WRITE, biblio WRITE, marc_subfield_structure READ");
1152         my $sth = $dbh->prepare("Select max(biblioitemnumber) from biblioitems");
1153         my $data;
1154         my $biblioitemnumber;
1155
1156         $sth->execute;
1157         $data       = $sth->fetchrow_arrayref;
1158         $biblioitemnumber = $$data[0] + 1;
1159         
1160         # Insert biblioitemnumber in MARC record, we need it to manage items later...
1161         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblioitem->{biblionumber});
1162         my ($biblioitemnumberfield,$biblioitemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'biblioitems.biblioitemnumber',$frameworkcode);
1163         my $record = MARC::File::USMARC::decode($biblioitem->{marc});
1164         my $field=$record->field($biblioitemnumberfield);
1165         $field->update($biblioitemnumbersubfield => "$biblioitemnumber");
1166         $biblioitem->{marc} = $record->as_usmarc();
1167         $biblioitem->{marcxml} = $record->as_xml();
1168
1169         $sth = $dbh->prepare( "insert into biblioitems set
1170                                                                         biblioitemnumber = ?,           biblionumber     = ?,
1171                                                                         volume           = ?,                   number           = ?,
1172                                                                         classification  = ?,                    itemtype         = ?,
1173                                                                         url              = ?,                           isbn             = ?,
1174                                                                         issn             = ?,                           dewey            = ?,
1175                                                                         subclass         = ?,                           publicationyear  = ?,
1176                                                                         publishercode    = ?,           volumedate       = ?,
1177                                                                         volumeddesc      = ?,           illus            = ?,
1178                                                                         pages            = ?,                           notes            = ?,
1179                                                                         size             = ?,                           lccn             = ?,
1180                                                                         marc             = ?,                           place            = ?,
1181                                                                         marcxml          = ?"
1182         );
1183         $sth->execute(
1184                 $biblioitemnumber,               $biblioitem->{'biblionumber'},
1185                 $biblioitem->{'volume'},         $biblioitem->{'number'},
1186                 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
1187                 $biblioitem->{'url'},            $biblioitem->{'isbn'},
1188                 $biblioitem->{'issn'},           $biblioitem->{'dewey'},
1189                 $biblioitem->{'subclass'},       $biblioitem->{'publicationyear'},
1190                 $biblioitem->{'publishercode'},  $biblioitem->{'volumedate'},
1191                 $biblioitem->{'volumeddesc'},    $biblioitem->{'illus'},
1192                 $biblioitem->{'pages'},          $biblioitem->{'bnotes'},
1193                 $biblioitem->{'size'},           $biblioitem->{'lccn'},
1194                 $biblioitem->{'marc'},           $biblioitem->{'place'},
1195                 $biblioitem->{marcxml},
1196         );
1197         $dbh->do("unlock tables");
1198         zebra_create($biblioitem->{biblionumber}, $record);
1199         return ($biblioitemnumber);
1200 }
1201
1202 =head2 REALnewsubtitle($dbh,$bibnum,$subtitle);
1203
1204 =over 4
1205
1206 create a new subtitle
1207
1208 =back
1209
1210 =cut
1211 sub REALnewsubtitle {
1212     my ( $dbh, $bibnum, $subtitle ) = @_;
1213     my $sth =
1214       $dbh->prepare(
1215         "insert into bibliosubtitle set biblionumber = ?, subtitle = ?");
1216     $sth->execute( $bibnum, $subtitle ) if $subtitle;
1217     $sth->finish;
1218 }
1219
1220 =head2 ($itemnumber,$errors)= REALnewitems($dbh,$item,$barcode);
1221
1222 =over 4
1223
1224 create a item. $item is a hash and $barcode the barcode.
1225
1226 =back
1227
1228 =cut
1229
1230 sub REALnewitems {
1231     my ( $dbh, $item, $barcode ) = @_;
1232
1233 #       warn "OLDNEWITEMS";
1234         
1235         $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE,marc_subfield_structure WRITE');
1236     my $sth = $dbh->prepare("Select max(itemnumber) from items");
1237     my $data;
1238     my $itemnumber;
1239     my $error = "";
1240     $sth->execute;
1241     $data       = $sth->fetchrow_hashref;
1242     $itemnumber = $data->{'max(itemnumber)'} + 1;
1243
1244 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
1245     if ( $item->{'loan'} ) {
1246         $item->{'notforloan'} = $item->{'loan'};
1247     }
1248
1249     # if dateaccessioned is provided, use it. Otherwise, set to NOW()
1250     if ( $item->{'dateaccessioned'} ) {
1251         $sth = $dbh->prepare( "Insert into items set
1252                                                         itemnumber           = ?,                       biblionumber         = ?,
1253                                                         multivolumepart      = ?,
1254                                                         biblioitemnumber     = ?,                       barcode              = ?,
1255                                                         booksellerid         = ?,                       dateaccessioned      = ?,
1256                                                         homebranch           = ?,                       holdingbranch        = ?,
1257                                                         price                = ?,                       replacementprice     = ?,
1258                                                         replacementpricedate = NOW(),           datelastseen            = NOW(),
1259                                                         multivolume                     = ?,                    stack                           = ?,
1260                                                         itemlost                        = ?,                    wthdrawn                        = ?,
1261                                                         paidfor                         = ?,                    itemnotes            = ?,
1262                                                         itemcallnumber  =?,                                                     notforloan = ?,
1263                                                         location = ?
1264                                                         "
1265         );
1266         $sth->execute(
1267                         $itemnumber,                            $item->{'biblionumber'},
1268                         $item->{'multivolumepart'},
1269                         $item->{'biblioitemnumber'},$item->{barcode},
1270                         $item->{'booksellerid'},        $item->{'dateaccessioned'},
1271                         $item->{'homebranch'},          $item->{'holdingbranch'},
1272                         $item->{'price'},                       $item->{'replacementprice'},
1273                         $item->{multivolume},           $item->{stack},
1274                         $item->{itemlost},                      $item->{wthdrawn},
1275                         $item->{paidfor},                       $item->{'itemnotes'},
1276                         $item->{'itemcallnumber'},      $item->{'notforloan'},
1277                         $item->{'location'}
1278         );
1279                 if ( defined $sth->errstr ) {
1280                         $error .= $sth->errstr;
1281                 }
1282     }
1283     else {
1284         $sth = $dbh->prepare( "Insert into items set
1285                                                         itemnumber           = ?,                       biblionumber         = ?,
1286                                                         multivolumepart      = ?,
1287                                                         biblioitemnumber     = ?,                       barcode              = ?,
1288                                                         booksellerid         = ?,                       dateaccessioned      = NOW(),
1289                                                         homebranch           = ?,                       holdingbranch        = ?,
1290                                                         price                = ?,                       replacementprice     = ?,
1291                                                         replacementpricedate = NOW(),           datelastseen            = NOW(),
1292                                                         multivolume                     = ?,                    stack                           = ?,
1293                                                         itemlost                        = ?,                    wthdrawn                        = ?,
1294                                                         paidfor                         = ?,                    itemnotes            = ?,
1295                                                         itemcallnumber  =?,                                                     notforloan = ?,
1296                                                         location = ?
1297                                                         "
1298         );
1299         $sth->execute(
1300                         $itemnumber,                            $item->{'biblionumber'},
1301                         $item->{'multivolumepart'},
1302                         $item->{'biblioitemnumber'},$item->{barcode},
1303                         $item->{'booksellerid'},
1304                         $item->{'homebranch'},          $item->{'holdingbranch'},
1305                         $item->{'price'},                       $item->{'replacementprice'},
1306                         $item->{multivolume},           $item->{stack},
1307                         $item->{itemlost},                      $item->{wthdrawn},
1308                         $item->{paidfor},                       $item->{'itemnotes'},
1309                         $item->{'itemcallnumber'},      $item->{'notforloan'},
1310                         $item->{'location'}
1311         );
1312                 if ( defined $sth->errstr ) {
1313                         $error .= $sth->errstr;
1314                 }
1315     }
1316         # item stored, now, deal with the marc part...
1317         $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
1318                                                         where   biblio.biblionumber=biblioitems.biblionumber and 
1319                                                                         biblio.biblionumber=?");
1320         $sth->execute($item->{biblionumber});
1321     if ( defined $sth->errstr ) {
1322         $error .= $sth->errstr;
1323     }
1324         my ($rawmarc,$frameworkcode) = $sth->fetchrow;
1325         warn "ERROR IN REALnewitem, MARC record not found FOR $item->{biblionumber} => $rawmarc <=" unless $rawmarc;
1326         my $record = MARC::File::USMARC::decode($rawmarc);
1327         # ok, we have the marc record, add item number to the item field (in {marc}, and add the field to the record)
1328         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
1329         my $itemrecord = MARC::File::USMARC::decode($item->{marc});
1330         my $itemfield = $itemrecord->field($itemnumberfield);
1331         $itemfield->add_subfields($itemnumbersubfield => "$itemnumber");
1332         $record->insert_grouped_field($itemfield);
1333         # save the record into biblioitem
1334         $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=?");
1335         $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber});
1336     if ( defined $sth->errstr ) {
1337         $error .= $sth->errstr;
1338     }
1339         zebra_create($item->{biblionumber},$record);
1340         $dbh->do('unlock tables');
1341     return ( $itemnumber, $error );
1342 }
1343
1344 =head2 REALmoditem($dbh,$item);
1345
1346 =over 4
1347
1348 modify item
1349
1350 =back
1351
1352 =cut
1353
1354 sub REALmoditem {
1355     my ( $dbh, $item ) = @_;
1356         my $error;
1357         $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE');
1358     $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
1359     my $query = "update items set  barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
1360     my @bind = (
1361         $item->{'barcode'},                     $item->{'itemnotes'},
1362         $item->{'itemcallnumber'},      $item->{'notforloan'},
1363         $item->{'location'},            $item->{multivolumepart},
1364                 $item->{multivolume},           $item->{stack},
1365                 $item->{wthdrawn},
1366     );
1367     if ( $item->{'lost'} ne '' ) {
1368         $query = "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
1369                                                         itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
1370                                                         location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
1371         @bind = (
1372             $item->{'bibitemnum'},     $item->{'barcode'},
1373             $item->{'itemnotes'},          $item->{'homebranch'},
1374             $item->{'lost'},           $item->{'wthdrawn'},
1375             $item->{'itemcallnumber'}, $item->{'notforloan'},
1376             $item->{'location'},                $item->{multivolumepart},
1377                         $item->{multivolume},           $item->{stack},
1378                         $item->{wthdrawn},
1379         );
1380                 if ($item->{homebranch}) {
1381                         $query.=",homebranch=?";
1382                         push @bind, $item->{homebranch};
1383                 }
1384                 if ($item->{holdingbranch}) {
1385                         $query.=",holdingbranch=?";
1386                         push @bind, $item->{holdingbranch};
1387                 }
1388     }
1389         $query.=" where itemnumber=?";
1390         push @bind,$item->{'itemnum'};
1391    if ( $item->{'replacement'} ne '' ) {
1392         $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
1393     }
1394     my $sth = $dbh->prepare($query);
1395     $sth->execute(@bind);
1396         
1397         # item stored, now, deal with the marc part...
1398         $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
1399                                                         where   biblio.biblionumber=biblioitems.biblionumber and 
1400                                                                         biblio.biblionumber=? and 
1401                                                                         biblioitems.biblioitemnumber=?");
1402         $sth->execute($item->{biblionumber},$item->{biblioitemnumber});
1403     if ( defined $sth->errstr ) {
1404         $error .= $sth->errstr;
1405     }
1406         my ($rawmarc,$frameworkcode) = $sth->fetchrow;
1407         warn "ERROR IN REALmoditem, MARC record not found" unless $rawmarc;
1408         my $record = MARC::File::USMARC::decode($rawmarc);
1409         # ok, we have the marc record, find the previous item record for this itemnumber and delete it
1410         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
1411         # prepare the new item record
1412         my $itemrecord = MARC::File::USMARC::decode($item->{marc});
1413         my $itemfield = $itemrecord->field($itemnumberfield);
1414         $itemfield->add_subfields($itemnumbersubfield => '$itemnumber');
1415         # parse all fields fields from the complete record
1416         foreach ($record->field($itemnumberfield)) {
1417                 # when the previous field is found, replace by the new one
1418                 if ($_->subfield($itemnumbersubfield) == $item->{itemnum}) {
1419                         $_->replace_with($itemfield);
1420                 }
1421         }
1422 #       $record->insert_grouped_field($itemfield);
1423         # save the record into biblioitem
1424         $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=? and biblioitemnumber=?");
1425         $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber},$item->{biblioitemnumber});
1426         zebra_create($item->biblionumber,$record);
1427     if ( defined $sth->errstr ) {
1428         $error .= $sth->errstr;
1429     }
1430         $dbh->do('unlock tables');
1431
1432     #  $dbh->disconnect;
1433 }
1434
1435 =head2 REALdelitem($dbh,$itemnum);
1436
1437 =over 4
1438
1439 delete item
1440
1441 =back
1442
1443 =cut
1444
1445 sub REALdelitem {
1446     my ( $dbh, $itemnum ) = @_;
1447
1448     #  my $dbh=C4Connect;
1449     my $sth = $dbh->prepare("select * from items where itemnumber=?");
1450     $sth->execute($itemnum);
1451     my $data = $sth->fetchrow_hashref;
1452     $sth->finish;
1453     my $query = "Insert into deleteditems set ";
1454     my @bind  = ();
1455     foreach my $temp ( keys %$data ) {
1456         $query .= "$temp = ?,";
1457         push ( @bind, $data->{$temp} );
1458     }
1459     $query =~ s/\,$//;
1460
1461     #  print $query;
1462     $sth = $dbh->prepare($query);
1463     $sth->execute(@bind);
1464     $sth->finish;
1465     $sth = $dbh->prepare("Delete from items where itemnumber=?");
1466     $sth->execute($itemnum);
1467     $sth->finish;
1468
1469     #  $dbh->disconnect;
1470 }
1471
1472 =head2 REALdelbiblioitem($dbh,$biblioitemnumber);
1473
1474 =over 4
1475
1476 deletes a biblioitem
1477 NOTE : not standard sub name. Should be REALdelbiblioitem()
1478
1479 =back
1480
1481 =cut
1482
1483 sub REALdelbiblioitem {
1484     my ( $dbh, $biblioitemnumber ) = @_;
1485
1486     #    my $dbh   = C4Connect;
1487     my $sth = $dbh->prepare( "Select * from biblioitems
1488 where biblioitemnumber = ?"
1489     );
1490     my $results;
1491
1492     $sth->execute($biblioitemnumber);
1493
1494     if ( $results = $sth->fetchrow_hashref ) {
1495         $sth->finish;
1496         $sth =
1497           $dbh->prepare(
1498 "Insert into deletedbiblioitems (biblioitemnumber, biblionumber, volume, number, classification, itemtype,
1499                                         isbn, issn ,dewey ,subclass ,publicationyear ,publishercode ,volumedate ,volumeddesc ,timestamp ,illus ,
1500                                         pages ,notes ,size ,url ,lccn ) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
1501         );
1502
1503         $sth->execute(
1504             $results->{biblioitemnumber}, $results->{biblionumber},
1505             $results->{volume},           $results->{number},
1506             $results->{classification},   $results->{itemtype},
1507             $results->{isbn},             $results->{issn},
1508             $results->{dewey},            $results->{subclass},
1509             $results->{publicationyear},  $results->{publishercode},
1510             $results->{volumedate},       $results->{volumeddesc},
1511             $results->{timestamp},        $results->{illus},
1512             $results->{pages},            $results->{notes},
1513             $results->{size},             $results->{url},
1514             $results->{lccn}
1515         );
1516         my $sth2 =
1517           $dbh->prepare("Delete from biblioitems where biblioitemnumber = ?");
1518         $sth2->execute($biblioitemnumber);
1519         $sth2->finish();
1520     }    # if
1521     $sth->finish;
1522
1523     # Now delete all the items attached to the biblioitem
1524     $sth = $dbh->prepare("Select * from items where biblioitemnumber = ?");
1525     $sth->execute($biblioitemnumber);
1526     my @results;
1527     while ( my $data = $sth->fetchrow_hashref ) {
1528         my $query = "Insert into deleteditems set ";
1529         my @bind  = ();
1530         foreach my $temp ( keys %$data ) {
1531             $query .= "$temp = ?,";
1532             push ( @bind, $data->{$temp} );
1533         }
1534         $query =~ s/\,$//;
1535         my $sth2 = $dbh->prepare($query);
1536         $sth2->execute(@bind);
1537     }    # while
1538     $sth->finish;
1539     $sth = $dbh->prepare("Delete from items where biblioitemnumber = ?");
1540     $sth->execute($biblioitemnumber);
1541     $sth->finish();
1542
1543     #    $dbh->disconnect;
1544 }    # sub deletebiblioitem
1545
1546 =head2 REALdelbiblio($dbh,$biblio);
1547
1548 =over 4
1549
1550 delete a biblio
1551
1552 =back
1553
1554 =cut
1555
1556 sub REALdelbiblio {
1557     my ( $dbh, $biblio ) = @_;
1558     my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
1559     $sth->execute($biblio);
1560     if ( my $data = $sth->fetchrow_hashref ) {
1561         $sth->finish;
1562         my $query = "Insert into deletedbiblio set ";
1563         my @bind  = ();
1564         foreach my $temp ( keys %$data ) {
1565             $query .= "$temp = ?,";
1566             push ( @bind, $data->{$temp} );
1567         }
1568
1569         #replacing the last , by ",?)"
1570         $query =~ s/\,$//;
1571         $sth = $dbh->prepare($query);
1572         $sth->execute(@bind);
1573         $sth->finish;
1574         $sth = $dbh->prepare("Delete from biblio where biblionumber=?");
1575         $sth->execute($biblio);
1576         $sth->finish;
1577     }
1578     $sth->finish;
1579 }
1580
1581 =head2 $number = itemcount($biblio);
1582
1583 =over 4
1584
1585 returns the number of items attached to a biblio
1586
1587 =back
1588
1589 =cut
1590
1591 sub itemcount {
1592     my ($biblio) = @_;
1593     my $dbh = C4::Context->dbh;
1594
1595     #  print $query;
1596     my $sth = $dbh->prepare("Select count(*) from items where biblionumber=?");
1597     $sth->execute($biblio);
1598     my $data = $sth->fetchrow_hashref;
1599     $sth->finish;
1600     return ( $data->{'count(*)'} );
1601 }
1602
1603 =head2 $biblionumber = newbiblio($biblio);
1604
1605 =over 4
1606
1607 create a biblio. The parameter is a hash
1608
1609 =back
1610
1611 =cut
1612
1613 sub newbiblio {
1614     my ($biblio) = @_;
1615     my $dbh    = C4::Context->dbh;
1616     my $bibnum = REALnewbiblio( $dbh, $biblio );
1617     # finds new (MARC bibid
1618     #   my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
1619 #     my $record = &MARCkoha2marcBiblio( $dbh, $bibnum );
1620 #     MARCaddbiblio( $dbh, $record, $bibnum,'' );
1621     return ($bibnum);
1622 }
1623
1624 =head2   $biblionumber = &modbiblio($biblio);
1625
1626 =over 4
1627
1628 Update a biblio record.
1629
1630 C<$biblio> is a reference-to-hash whose keys are the fields in the
1631 biblio table in the Koha database. All fields must be present, not
1632 just the ones you wish to change.
1633
1634 C<&modbiblio> updates the record defined by
1635 C<$biblio-E<gt>{biblionumber}> with the values in C<$biblio>.
1636
1637 C<&modbiblio> returns C<$biblio-E<gt>{biblionumber}> whether it was
1638 successful or not.
1639
1640 =back
1641
1642 =cut
1643
1644 sub modbiblio {
1645         my ($biblio) = @_;
1646         my $dbh  = C4::Context->dbh;
1647         my $biblionumber=REALmodbiblio($dbh,$biblio);
1648         my $record = MARCkoha2marcBiblio($dbh,$biblionumber,$biblionumber);
1649         # finds new (MARC bibid
1650         my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$biblionumber);
1651         MARCmodbiblio($dbh,$bibid,$record,"",0);
1652         return($biblionumber);
1653 } # sub modbiblio
1654
1655 =head2   &modsubtitle($biblionumber, $subtitle);
1656
1657 =over 4
1658
1659 Sets the subtitle of a book.
1660
1661 C<$biblionumber> is the biblionumber of the book to modify.
1662
1663 C<$subtitle> is the new subtitle.
1664
1665 =back
1666
1667 =cut
1668
1669 sub modsubtitle {
1670     my ( $bibnum, $subtitle ) = @_;
1671     my $dbh = C4::Context->dbh;
1672     &REALmodsubtitle( $dbh, $bibnum, $subtitle );
1673 }    # sub modsubtitle
1674
1675 =head2 &modaddauthor($biblionumber, $author);
1676
1677 =over 4
1678
1679 Replaces all additional authors for the book with biblio number
1680 C<$biblionumber> with C<$author>. If C<$author> is the empty string,
1681 C<&modaddauthor> deletes all additional authors.
1682
1683 =back
1684
1685 =cut
1686
1687 sub modaddauthor {
1688     my ( $bibnum, @authors ) = @_;
1689     my $dbh = C4::Context->dbh;
1690     &REALmodaddauthor( $dbh, $bibnum, @authors );
1691 }    # sub modaddauthor
1692
1693 =head2 $error = &modsubject($biblionumber, $force, @subjects);
1694
1695 =over 4
1696
1697 $force - a subject to force
1698 $error - Error message, or undef if successful.
1699
1700 =back
1701
1702 =cut
1703
1704 sub modsubject {
1705     my ( $bibnum, $force, @subject ) = @_;
1706     my $dbh = C4::Context->dbh;
1707     my $error = &REALmodsubject( $dbh, $bibnum, $force, @subject );
1708     if ($error eq ''){
1709                 # When MARC is off, ensures that the MARC biblio table gets updated with new
1710                 # subjects, of course, it deletes the biblio in marc, and then recreates.
1711                 # This check is to ensure that no MARC data exists to lose.
1712 #               if (C4::Context->preference("MARC") eq '0'){
1713 #               warn "in modSUBJECT";
1714 #                       my $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibnum);
1715 #                       my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
1716 #                       &MARCmodbiblio($dbh,$bibid, $MARCRecord);
1717 #               }
1718         }
1719         return ($error);
1720 }    # sub modsubject
1721
1722 =head2 modbibitem($biblioitem);
1723
1724 =over 4
1725
1726 modify a biblioitem. The parameter is a hash
1727
1728 =back
1729
1730 =cut
1731
1732 sub modbibitem {
1733     my ($biblioitem) = @_;
1734     my $dbh = C4::Context->dbh;
1735     &REALmodbiblioitem( $dbh, $biblioitem );
1736 }    # sub modbibitem
1737
1738 =head2 $biblioitemnumber = newbiblioitem($biblioitem)
1739
1740 =over 4
1741
1742 create a biblioitem, the parameter is a hash
1743
1744 =back
1745
1746 =cut
1747
1748 sub newbiblioitem {
1749     my ($biblioitem) = @_;
1750     my $dbh        = C4::Context->dbh;
1751         # add biblio information to the hash
1752     my $MARCbiblio = MARCkoha2marcBiblio( $dbh, $biblioitem );
1753         $biblioitem->{marc} = $MARCbiblio->as_usmarc();
1754     my $bibitemnum = &REALnewbiblioitem( $dbh, $biblioitem );
1755     return ($bibitemnum);
1756 }
1757
1758 =head2 newsubtitle($biblionumber,$subtitle);
1759
1760 =over 4
1761
1762 insert a subtitle for $biblionumber biblio
1763
1764 =back
1765
1766 =cut
1767
1768
1769 sub newsubtitle {
1770     my ( $bibnum, $subtitle ) = @_;
1771     my $dbh = C4::Context->dbh;
1772     &REALnewsubtitle( $dbh, $bibnum, $subtitle );
1773 }
1774
1775 =head2 $errors = newitems($item, @barcodes);
1776
1777 =over 4
1778
1779 insert items ($item is a hash)
1780
1781 =back
1782
1783 =cut
1784
1785
1786 sub newitems {
1787     my ( $item, @barcodes ) = @_;
1788     my $dbh = C4::Context->dbh;
1789     my $errors;
1790     my $itemnumber;
1791     my $error;
1792     foreach my $barcode (@barcodes) {
1793                 # add items, one by one for each barcode.
1794                 my $oneitem=$item;
1795                 $oneitem->{barcode}= $barcode;
1796         my $MARCitem = &MARCkoha2marcItem( $dbh, $oneitem);
1797                 $oneitem->{marc} = $MARCitem->as_usmarc;
1798         ( $itemnumber, $error ) = &REALnewitems( $dbh, $oneitem);
1799 #         $errors .= $error;
1800 #         &MARCadditem( $dbh, $MARCitem, $item->{biblionumber} );
1801     }
1802     return ($errors);
1803 }
1804
1805 =head2 moditem($item);
1806
1807 =over 4
1808
1809 modify an item ($item is a hash with all item informations)
1810
1811 =back
1812
1813 =cut
1814
1815
1816 sub moditem {
1817     my ($item) = @_;
1818     my $dbh = C4::Context->dbh;
1819     &REALmoditem( $dbh, $item );
1820     my $MARCitem =
1821       &MARCkoha2marcItem( $dbh, $item->{'biblionumber'}, $item->{'itemnum'} );
1822     my $bibid =
1823       &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $item->{biblionumber} );
1824     &MARCmoditem( $dbh, $MARCitem, $bibid, $item->{itemnum}, 0 );
1825 }
1826
1827 =head2 $error = checkitems($count,@barcodes);
1828
1829 =over 4
1830
1831 check for each @barcode entry that the barcode is not a duplicate
1832
1833 =back
1834
1835 =cut
1836
1837 sub checkitems {
1838     my ( $count, @barcodes ) = @_;
1839     my $dbh = C4::Context->dbh;
1840     my $error;
1841     my $sth = $dbh->prepare("Select * from items where barcode=?");
1842     for ( my $i = 0 ; $i < $count ; $i++ ) {
1843         $barcodes[$i] = uc $barcodes[$i];
1844         $sth->execute( $barcodes[$i] );
1845         if ( my $data = $sth->fetchrow_hashref ) {
1846             $error .= " Duplicate Barcode: $barcodes[$i]";
1847         }
1848     }
1849     $sth->finish;
1850     return ($error);
1851 }
1852
1853 =head2 $delitem($itemnum);
1854
1855 =over 4
1856
1857 delete item $itemnum being the item number to delete
1858
1859 =back
1860
1861 =cut
1862
1863 sub delitem {
1864     my ($itemnum) = @_;
1865     my $dbh = C4::Context->dbh;
1866     &REALdelitem( $dbh, $itemnum );
1867 }
1868
1869 =head2 deletebiblioitem($biblioitemnumber);
1870
1871 =over 4
1872
1873 delete the biblioitem $biblioitemnumber
1874
1875 =back
1876
1877 =cut
1878
1879 sub deletebiblioitem {
1880     my ($biblioitemnumber) = @_;
1881     my $dbh = C4::Context->dbh;
1882     &REALdelbiblioitem( $dbh, $biblioitemnumber );
1883 }    # sub deletebiblioitem
1884
1885 =head2 delbiblio($biblionumber)
1886
1887 =over 4
1888
1889 delete biblio $biblionumber
1890
1891 =back
1892
1893 =cut
1894
1895 sub delbiblio {
1896     my ($biblio) = @_;
1897     my $dbh = C4::Context->dbh;
1898     &REALdelbiblio( $dbh, $biblio );
1899     my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $biblio );
1900     &MARCdelbiblio( $dbh, $bibid, 0 );
1901 }
1902
1903 =head2 ($count,@results) = getbiblio($biblionumber);
1904
1905 =over 4
1906
1907 return an array with hash of biblios.
1908
1909 FIXME : biblionumber being the primary key, this sub will always return only 1 result, API should be modified...
1910
1911 =back
1912
1913 =cut
1914
1915 sub getbiblio {
1916     my ($biblionumber) = @_;
1917     my $dbh = C4::Context->dbh;
1918     my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
1919
1920     # || die "Cannot prepare $query\n" . $dbh->errstr;
1921     my $count = 0;
1922     my @results;
1923
1924     $sth->execute($biblionumber);
1925
1926     # || die "Cannot execute $query\n" . $sth->errstr;
1927     while ( my $data = $sth->fetchrow_hashref ) {
1928         $results[$count] = $data;
1929         $count++;
1930     }    # while
1931
1932     $sth->finish;
1933     return ( $count, @results );
1934 }    # sub getbiblio
1935
1936 =item bibdata
1937
1938   $data = &bibdata($biblionumber, $type);
1939
1940 Returns information about the book with the given biblionumber.
1941
1942 C<$type> is ignored.
1943
1944 C<&bibdata> returns a reference-to-hash. The keys are the fields in
1945 the C<biblio>, C<biblioitems>, and C<bibliosubtitle> tables in the
1946 Koha database.
1947
1948 In addition, C<$data-E<gt>{subject}> is the list of the book's
1949 subjects, separated by C<" , "> (space, comma, space).
1950
1951 If there are multiple biblioitems with the given biblionumber, only
1952 the first one is considered.
1953
1954 =cut
1955 #'
1956 sub bibdata {
1957         my ($bibnum, $type) = @_;
1958         my $dbh   = C4::Context->dbh;
1959         my $sth   = $dbh->prepare("Select *, biblioitems.notes AS bnotes, biblio.notes
1960                                                                 from biblio 
1961                                                                 left join biblioitems on biblioitems.biblionumber = biblio.biblionumber
1962                                                                 left join bibliosubtitle on
1963                                                                 biblio.biblionumber = bibliosubtitle.biblionumber
1964                                                                 left join itemtypes on biblioitems.itemtype=itemtypes.itemtype
1965                                                                 where biblio.biblionumber = ?
1966                                                                 ");
1967         $sth->execute($bibnum);
1968         my $data;
1969         $data  = $sth->fetchrow_hashref;
1970         $sth->finish;
1971         # handle management of repeated subtitle
1972         $sth   = $dbh->prepare("Select * from bibliosubtitle where biblionumber = ?");
1973         $sth->execute($bibnum);
1974         my @subtitles;
1975         while (my $dat = $sth->fetchrow_hashref){
1976                 my %line;
1977                 $line{subtitle} = $dat->{subtitle};
1978                 push @subtitles, \%line;
1979         } # while
1980         $data->{subtitles} = \@subtitles;
1981         $sth->finish;
1982         $sth   = $dbh->prepare("Select * from bibliosubject where biblionumber = ?");
1983         $sth->execute($bibnum);
1984         my @subjects;
1985         while (my $dat = $sth->fetchrow_hashref){
1986                 my %line;
1987                 $line{subject} = $dat->{'subject'};
1988                 push @subjects, \%line;
1989         } # while
1990         $data->{subjects} = \@subjects;
1991         $sth->finish;
1992         $sth   = $dbh->prepare("Select * from additionalauthors where biblionumber = ?");
1993         $sth->execute($bibnum);
1994         while (my $dat = $sth->fetchrow_hashref){
1995                 $data->{'additionalauthors'} .= "$dat->{'author'} - ";
1996         } # while
1997         chop $data->{'additionalauthors'};
1998         chop $data->{'additionalauthors'};
1999         chop $data->{'additionalauthors'};
2000         $sth->finish;
2001         return($data);
2002 } # sub bibdata
2003
2004 =head2 ($count,@results) = getbiblioitem($biblioitemnumber);
2005
2006 =over 4
2007
2008 return an array with hash of biblioitemss.
2009
2010 FIXME : biblioitemnumber being unique, this sub will always return only 1 result, API should be modified...
2011
2012 =back
2013
2014 =cut
2015
2016 sub getbiblioitem {
2017     my ($biblioitemnum) = @_;
2018     my $dbh = C4::Context->dbh;
2019     my $sth = $dbh->prepare( "Select * from biblioitems where
2020 biblioitemnumber = ?"
2021     );
2022     my $count = 0;
2023     my @results;
2024
2025     $sth->execute($biblioitemnum);
2026
2027     while ( my $data = $sth->fetchrow_hashref ) {
2028         $results[$count] = $data;
2029         $count++;
2030     }    # while
2031
2032     $sth->finish;
2033     return ( $count, @results );
2034 }    # sub getbiblioitem
2035
2036 =head2 ($count,@results) = getbiblioitembybiblionumber($biblionumber);
2037
2038 =over 4
2039
2040 return an array with hash of biblioitems for the given biblionumber.
2041
2042 =back
2043
2044 =cut
2045
2046 sub getbiblioitembybiblionumber {
2047     my ($biblionumber) = @_;
2048     my $dbh = C4::Context->dbh;
2049     my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
2050     my $count = 0;
2051     my @results;
2052
2053     $sth->execute($biblionumber);
2054
2055     while ( my $data = $sth->fetchrow_hashref ) {
2056         $results[$count] = $data;
2057         $count++;
2058     }    # while
2059
2060     $sth->finish;
2061     return ( $count, @results );
2062 }    # sub
2063
2064 =head2 ($count,@results) = getitemsbybiblioitem($biblionumber);
2065
2066 =over 4
2067
2068 returns an array with hash of items
2069
2070 =back
2071
2072 =cut
2073
2074 sub getitemsbybiblioitem {
2075     my ($biblioitemnum) = @_;
2076     my $dbh = C4::Context->dbh;
2077     my $sth = $dbh->prepare( "Select * from items, biblio where
2078 biblio.biblionumber = items.biblionumber and biblioitemnumber
2079 = ?"
2080     );
2081
2082     # || die "Cannot prepare $query\n" . $dbh->errstr;
2083     my $count = 0;
2084     my @results;
2085
2086     $sth->execute($biblioitemnum);
2087
2088     # || die "Cannot execute $query\n" . $sth->errstr;
2089     while ( my $data = $sth->fetchrow_hashref ) {
2090         $results[$count] = $data;
2091         $count++;
2092     }    # while
2093
2094     $sth->finish;
2095     return ( $count, @results );
2096 }    # sub getitemsbybiblioitem
2097
2098 =item ItemInfo
2099
2100   @results = &ItemInfo($env, $biblionumber, $type);
2101
2102 Returns information about books with the given biblionumber.
2103
2104 C<$type> may be either C<intra> or anything else. If it is not set to
2105 C<intra>, then the search will exclude lost, very overdue, and
2106 withdrawn items.
2107
2108 C<$env> is ignored.
2109
2110 C<&ItemInfo> returns a list of references-to-hash. Each element
2111 contains a number of keys. Most of them are table items from the
2112 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
2113 Koha database. Other keys include:
2114
2115 =over 4
2116
2117 =item C<$data-E<gt>{branchname}>
2118
2119 The name (not the code) of the branch to which the book belongs.
2120
2121 =item C<$data-E<gt>{datelastseen}>
2122
2123 This is simply C<items.datelastseen>, except that while the date is
2124 stored in YYYY-MM-DD format in the database, here it is converted to
2125 DD/MM/YYYY format. A NULL date is returned as C<//>.
2126
2127 =item C<$data-E<gt>{datedue}>
2128
2129 =item C<$data-E<gt>{class}>
2130
2131 This is the concatenation of C<biblioitems.classification>, the book's
2132 Dewey code, and C<biblioitems.subclass>.
2133
2134 =item C<$data-E<gt>{ocount}>
2135
2136 I think this is the number of copies of the book available.
2137
2138 =item C<$data-E<gt>{order}>
2139
2140 If this is set, it is set to C<One Order>.
2141
2142 =back
2143
2144 =cut
2145 #'
2146 sub ItemInfo {
2147         my ($env,$biblionumber,$type) = @_;
2148         my $dbh   = C4::Context->dbh;
2149         my $query = "SELECT *,items.notforloan as itemnotforloan FROM items, biblio, biblioitems 
2150                                         left join itemtypes on biblioitems.itemtype = itemtypes.itemtype
2151                                         WHERE items.biblionumber = ?
2152                                         AND biblioitems.biblioitemnumber = items.biblioitemnumber
2153                                         AND biblio.biblionumber = items.biblionumber";
2154         $query .= " order by items.dateaccessioned desc";
2155         my $sth=$dbh->prepare($query);
2156         $sth->execute($biblionumber);
2157         my $i=0;
2158         my @results;
2159         while (my $data=$sth->fetchrow_hashref){
2160                 my $datedue = '';
2161                 my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber from issues,borrowers where itemnumber = ? and returndate is null and issues.borrowernumber=borrowers.borrowernumber");
2162                 $isth->execute($data->{'itemnumber'});
2163                 if (my $idata=$isth->fetchrow_hashref){
2164                 $data->{borrowernumber} = $idata->{borrowernumber};
2165                 $data->{cardnumber} = $idata->{cardnumber};
2166                 $datedue = format_date($idata->{'date_due'});
2167                 }
2168                 if ($datedue eq ''){
2169                         my ($restype,$reserves)=C4::Reserves2::CheckReserves($data->{'itemnumber'});
2170                         if ($restype) {
2171                                 $datedue=$restype;
2172                         }
2173                 }
2174                 $isth->finish;
2175         #get branch information.....
2176                 my $bsth=$dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
2177                 $bsth->execute($data->{'holdingbranch'});
2178                 if (my $bdata=$bsth->fetchrow_hashref){
2179                         $data->{'branchname'} = $bdata->{'branchname'};
2180                 }
2181                 my $date=format_date($data->{'datelastseen'});
2182                 $data->{'datelastseen'}=$date;
2183                 $data->{'datedue'}=$datedue;
2184         # get notforloan complete status if applicable
2185                 my $sthnflstatus = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield="items.notforloan"');
2186                 $sthnflstatus->execute;
2187                 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
2188                 if ($authorised_valuecode) {
2189                         $sthnflstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
2190                         $sthnflstatus->execute($authorised_valuecode,$data->{itemnotforloan});
2191                         my ($lib) = $sthnflstatus->fetchrow;
2192                         $data->{notforloan} = $lib;
2193                 }
2194                 $results[$i]=$data;
2195                 $i++;
2196         }
2197         $sth->finish;
2198         return(@results);
2199 }
2200
2201 =item bibitems
2202
2203   ($count, @results) = &bibitems($biblionumber);
2204
2205 Given the biblionumber for a book, C<&bibitems> looks up that book's
2206 biblioitems (different publications of the same book, the audio book
2207 and film versions, etc.).
2208
2209 C<$count> is the number of elements in C<@results>.
2210
2211 C<@results> is an array of references-to-hash; the keys are the fields
2212 of the C<biblioitems> and C<itemtypes> tables of the Koha database. In
2213 addition, C<itemlost> indicates the availability of the item: if it is
2214 "2", then all copies of the item are long overdue; if it is "1", then
2215 all copies are lost; otherwise, there is at least one copy available.
2216
2217 =cut
2218 #'
2219 sub bibitems {
2220     my ($bibnum) = @_;
2221     my $dbh   = C4::Context->dbh;
2222     my $sth   = $dbh->prepare("SELECT biblioitems.*,
2223                         itemtypes.*,
2224                         MIN(items.itemlost)        as itemlost,
2225                         MIN(items.dateaccessioned) as dateaccessioned
2226                           FROM biblioitems, itemtypes, items
2227                          WHERE biblioitems.biblionumber     = ?
2228                            AND biblioitems.itemtype         = itemtypes.itemtype
2229                            AND biblioitems.biblioitemnumber = items.biblioitemnumber
2230                       GROUP BY items.biblioitemnumber");
2231     my $count = 0;
2232     my @results;
2233     $sth->execute($bibnum);
2234     while (my $data = $sth->fetchrow_hashref) {
2235         $results[$count] = $data;
2236         $count++;
2237     } # while
2238     $sth->finish;
2239     return($count, @results);
2240 } # sub bibitems
2241
2242
2243 =item bibitemdata
2244
2245   $itemdata = &bibitemdata($biblioitemnumber);
2246
2247 Looks up the biblioitem with the given biblioitemnumber. Returns a
2248 reference-to-hash. The keys are the fields from the C<biblio>,
2249 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
2250 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
2251
2252 =cut
2253 #'
2254 sub bibitemdata {
2255     my ($bibitem) = @_;
2256     my $dbh   = C4::Context->dbh;
2257     my $sth   = $dbh->prepare("Select *,biblioitems.notes as bnotes from biblio, biblioitems,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype");
2258     my $data;
2259
2260     $sth->execute($bibitem);
2261
2262     $data = $sth->fetchrow_hashref;
2263
2264     $sth->finish;
2265     return($data);
2266 } # sub bibitemdata
2267
2268
2269 =item getbibliofromitemnumber
2270
2271   $item = &getbibliofromitemnumber($env, $dbh, $itemnumber);
2272
2273 Looks up the item with the given itemnumber.
2274
2275 C<$env> and C<$dbh> are ignored.
2276
2277 C<&itemnodata> returns a reference-to-hash whose keys are the fields
2278 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
2279 database.
2280
2281 =cut
2282 #'
2283 sub getbibliofromitemnumber {
2284   my ($env,$dbh,$itemnumber) = @_;
2285   $dbh = C4::Context->dbh;
2286   my $sth=$dbh->prepare("Select * from biblio,items,biblioitems
2287     where items.itemnumber = ?
2288     and biblio.biblionumber = items.biblionumber
2289     and biblioitems.biblioitemnumber = items.biblioitemnumber");
2290 #  print $query;
2291   $sth->execute($itemnumber);
2292   my $data=$sth->fetchrow_hashref;
2293   $sth->finish;
2294   return($data);
2295 }
2296
2297 =item barcodes
2298
2299   @barcodes = &barcodes($biblioitemnumber);
2300
2301 Given a biblioitemnumber, looks up the corresponding items.
2302
2303 Returns an array of references-to-hash; the keys are C<barcode> and
2304 C<itemlost>.
2305
2306 The returned items include very overdue items, but not lost ones.
2307
2308 =cut
2309 #'
2310 sub barcodes{
2311     #called from request.pl
2312     my ($biblioitemnumber)=@_;
2313     my $dbh = C4::Context->dbh;
2314     my $sth=$dbh->prepare("SELECT barcode, itemlost, holdingbranch FROM items
2315                            WHERE biblioitemnumber = ?
2316                              AND (wthdrawn <> 1 OR wthdrawn IS NULL)");
2317     $sth->execute($biblioitemnumber);
2318     my @barcodes;
2319     my $i=0;
2320     while (my $data=$sth->fetchrow_hashref){
2321         $barcodes[$i]=$data;
2322         $i++;
2323     }
2324     $sth->finish;
2325     return(@barcodes);
2326 }
2327
2328
2329 =item itemdata
2330
2331   $item = &itemdata($barcode);
2332
2333 Looks up the item with the given barcode, and returns a
2334 reference-to-hash containing information about that item. The keys of
2335 the hash are the fields from the C<items> and C<biblioitems> tables in
2336 the Koha database.
2337
2338 =cut
2339 #'
2340 sub get_item_from_barcode {
2341   my ($barcode)=@_;
2342   my $dbh = C4::Context->dbh;
2343   my $sth=$dbh->prepare("Select * from items,biblioitems where barcode=?
2344   and items.biblioitemnumber=biblioitems.biblioitemnumber");
2345   $sth->execute($barcode);
2346   my $data=$sth->fetchrow_hashref;
2347   $sth->finish;
2348   return($data);
2349 }
2350
2351
2352 =item itemissues
2353
2354   @issues = &itemissues($biblioitemnumber, $biblio);
2355
2356 Looks up information about who has borrowed the bookZ<>(s) with the
2357 given biblioitemnumber.
2358
2359 C<$biblio> is ignored.
2360
2361 C<&itemissues> returns an array of references-to-hash. The keys
2362 include the fields from the C<items> table in the Koha database.
2363 Additional keys include:
2364
2365 =over 4
2366
2367 =item C<date_due>
2368
2369 If the item is currently on loan, this gives the due date.
2370
2371 If the item is not on loan, then this is either "Available" or
2372 "Cancelled", if the item has been withdrawn.
2373
2374 =item C<card>
2375
2376 If the item is currently on loan, this gives the card number of the
2377 patron who currently has the item.
2378
2379 =item C<timestamp0>, C<timestamp1>, C<timestamp2>
2380
2381 These give the timestamp for the last three times the item was
2382 borrowed.
2383
2384 =item C<card0>, C<card1>, C<card2>
2385
2386 The card number of the last three patrons who borrowed this item.
2387
2388 =item C<borrower0>, C<borrower1>, C<borrower2>
2389
2390 The borrower number of the last three patrons who borrowed this item.
2391
2392 =back
2393
2394 =cut
2395 #'
2396 sub itemissues {
2397     my ($bibitem, $biblio)=@_;
2398     my $dbh   = C4::Context->dbh;
2399     # FIXME - If this function die()s, the script will abort, and the
2400     # user won't get anything; depending on how far the script has
2401     # gotten, the user might get a blank page. It would be much better
2402     # to at least print an error message. The easiest way to do this
2403     # is to set $SIG{__DIE__}.
2404     my $sth   = $dbh->prepare("Select * from items where
2405 items.biblioitemnumber = ?")
2406       || die $dbh->errstr;
2407     my $i     = 0;
2408     my @results;
2409
2410     $sth->execute($bibitem)
2411       || die $sth->errstr;
2412
2413     while (my $data = $sth->fetchrow_hashref) {
2414         # Find out who currently has this item.
2415         # FIXME - Wouldn't it be better to do this as a left join of
2416         # some sort? Currently, this code assumes that if
2417         # fetchrow_hashref() fails, then the book is on the shelf.
2418         # fetchrow_hashref() can fail for any number of reasons (e.g.,
2419         # database server crash), not just because no items match the
2420         # search criteria.
2421         my $sth2   = $dbh->prepare("select * from issues,borrowers
2422 where itemnumber = ?
2423 and returndate is NULL
2424 and issues.borrowernumber = borrowers.borrowernumber");
2425
2426         $sth2->execute($data->{'itemnumber'});
2427         if (my $data2 = $sth2->fetchrow_hashref) {
2428             $data->{'date_due'} = $data2->{'date_due'};
2429             $data->{'card'}     = $data2->{'cardnumber'};
2430             $data->{'borrower'}     = $data2->{'borrowernumber'};
2431         } else {
2432             if ($data->{'wthdrawn'} eq '1') {
2433                 $data->{'date_due'} = 'Cancelled';
2434             } else {
2435                 $data->{'date_due'} = 'Available';
2436             } # else
2437         } # else
2438
2439         $sth2->finish;
2440
2441         # Find the last 3 people who borrowed this item.
2442         $sth2 = $dbh->prepare("select * from issues, borrowers
2443                                                 where itemnumber = ?
2444                                                                         and issues.borrowernumber = borrowers.borrowernumber
2445                                                                         and returndate is not NULL
2446                                                                         order by returndate desc,timestamp desc") || die $dbh->errstr;
2447         $sth2->execute($data->{'itemnumber'}) || die $sth2->errstr;
2448         for (my $i2 = 0; $i2 < 2; $i2++) { # FIXME : error if there is less than 3 pple borrowing this item
2449             if (my $data2 = $sth2->fetchrow_hashref) {
2450                 $data->{"timestamp$i2"} = $data2->{'timestamp'};
2451                 $data->{"card$i2"}      = $data2->{'cardnumber'};
2452                 $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
2453             } # if
2454         } # for
2455
2456         $sth2->finish;
2457         $results[$i] = $data;
2458         $i++;
2459     }
2460
2461     $sth->finish;
2462     return(@results);
2463 }
2464
2465 =item getsubject
2466
2467   ($count, $subjects) = &getsubject($biblionumber);
2468
2469 Looks up the subjects of the book with the given biblionumber. Returns
2470 a two-element list. C<$subjects> is a reference-to-array, where each
2471 element is a subject of the book, and C<$count> is the number of
2472 elements in C<$subjects>.
2473
2474 =cut
2475 #'
2476 sub getsubject {
2477   my ($bibnum)=@_;
2478   my $dbh = C4::Context->dbh;
2479   my $sth=$dbh->prepare("Select * from bibliosubject where biblionumber=?");
2480   $sth->execute($bibnum);
2481   my @results;
2482   my $i=0;
2483   while (my $data=$sth->fetchrow_hashref){
2484     $results[$i]=$data;
2485     $i++;
2486   }
2487   $sth->finish;
2488   return($i,\@results);
2489 }
2490
2491 =item getaddauthor
2492
2493   ($count, $authors) = &getaddauthor($biblionumber);
2494
2495 Looks up the additional authors for the book with the given
2496 biblionumber.
2497
2498 Returns a two-element list. C<$authors> is a reference-to-array, where
2499 each element is an additional author, and C<$count> is the number of
2500 elements in C<$authors>.
2501
2502 =cut
2503 #'
2504 sub getaddauthor {
2505   my ($bibnum)=@_;
2506   my $dbh = C4::Context->dbh;
2507   my $sth=$dbh->prepare("Select * from additionalauthors where biblionumber=?");
2508   $sth->execute($bibnum);
2509   my @results;
2510   my $i=0;
2511   while (my $data=$sth->fetchrow_hashref){
2512     $results[$i]=$data;
2513     $i++;
2514   }
2515   $sth->finish;
2516   return($i,\@results);
2517 }
2518
2519
2520 =item getsubtitle
2521
2522   ($count, $subtitles) = &getsubtitle($biblionumber);
2523
2524 Looks up the subtitles for the book with the given biblionumber.
2525
2526 Returns a two-element list. C<$subtitles> is a reference-to-array,
2527 where each element is a subtitle, and C<$count> is the number of
2528 elements in C<$subtitles>.
2529
2530 =cut
2531 #'
2532 sub getsubtitle {
2533   my ($bibnum)=@_;
2534   my $dbh = C4::Context->dbh;
2535   my $sth=$dbh->prepare("Select * from bibliosubtitle where biblionumber=?");
2536   $sth->execute($bibnum);
2537   my @results;
2538   my $i=0;
2539   while (my $data=$sth->fetchrow_hashref){
2540     $results[$i]=$data;
2541     $i++;
2542   }
2543   $sth->finish;
2544   return($i,\@results);
2545 }
2546
2547
2548 =item getwebsites
2549
2550   ($count, @websites) = &getwebsites($biblionumber);
2551
2552 Looks up the web sites pertaining to the book with the given
2553 biblionumber.
2554
2555 C<$count> is the number of elements in C<@websites>.
2556
2557 C<@websites> is an array of references-to-hash; the keys are the
2558 fields from the C<websites> table in the Koha database.
2559
2560 =cut
2561 #FIXME : could maybe be deleted. Otherwise, would be better in a Websites.pm package
2562 #(with add / modify / delete subs)
2563
2564 sub getwebsites {
2565     my ($biblionumber) = @_;
2566     my $dbh   = C4::Context->dbh;
2567     my $sth   = $dbh->prepare("Select * from websites where biblionumber = ?");
2568     my $count = 0;
2569     my @results;
2570
2571     $sth->execute($biblionumber);
2572     while (my $data = $sth->fetchrow_hashref) {
2573         # FIXME - The URL scheme shouldn't be stripped off, at least
2574         # not here, since it's part of the URL, and will be useful in
2575         # constructing a link to the site. If you don't want the user
2576         # to see the "http://" part, strip that off when building the
2577         # HTML code.
2578         $data->{'url'} =~ s/^http:\/\///;       # FIXME - Leaning toothpick
2579                                                 # syndrome
2580         $results[$count] = $data;
2581         $count++;
2582     } # while
2583
2584     $sth->finish;
2585     return($count, @results);
2586 } # sub getwebsites
2587
2588 =item getwebbiblioitems
2589
2590   ($count, @results) = &getwebbiblioitems($biblionumber);
2591
2592 Given a book's biblionumber, looks up the web versions of the book
2593 (biblioitems with itemtype C<WEB>).
2594
2595 C<$count> is the number of items in C<@results>. C<@results> is an
2596 array of references-to-hash; the keys are the items from the
2597 C<biblioitems> table of the Koha database.
2598
2599 =cut
2600 #'
2601 sub getwebbiblioitems {
2602     my ($biblionumber) = @_;
2603     my $dbh   = C4::Context->dbh;
2604     my $sth   = $dbh->prepare("Select * from biblioitems where biblionumber = ?
2605 and itemtype = 'WEB'");
2606     my $count = 0;
2607     my @results;
2608
2609     $sth->execute($biblionumber);
2610     while (my $data = $sth->fetchrow_hashref) {
2611         $data->{'url'} =~ s/^http:\/\///;
2612         $results[$count] = $data;
2613         $count++;
2614     } # while
2615
2616     $sth->finish;
2617     return($count, @results);
2618 } # sub getwebbiblioitems
2619
2620 sub char_decode {
2621
2622     # converts ISO 5426 coded string to ISO 8859-1
2623     # sloppy code : should be improved in next issue
2624     my ( $string, $encoding ) = @_;
2625     $_ = $string;
2626
2627     #   $encoding = C4::Context->preference("marcflavour") unless $encoding;
2628     if ( $encoding eq "UNIMARC" ) {
2629 #         s/\xe1/Æ/gm;
2630         s/\xe2/Ð/gm;
2631         s/\xe9/Ø/gm;
2632         s/\xec/þ/gm;
2633         s/\xf1/æ/gm;
2634         s/\xf3/ð/gm;
2635         s/\xf9/ø/gm;
2636         s/\xfb/ß/gm;
2637         s/\xc1\x61/à/gm;
2638         s/\xc1\x65/è/gm;
2639         s/\xc1\x69/ì/gm;
2640         s/\xc1\x6f/ò/gm;
2641         s/\xc1\x75/ù/gm;
2642         s/\xc1\x41/À/gm;
2643         s/\xc1\x45/È/gm;
2644         s/\xc1\x49/Ì/gm;
2645         s/\xc1\x4f/Ò/gm;
2646         s/\xc1\x55/Ù/gm;
2647         s/\xc2\x41/Á/gm;
2648         s/\xc2\x45/É/gm;
2649         s/\xc2\x49/Í/gm;
2650         s/\xc2\x4f/Ó/gm;
2651         s/\xc2\x55/Ú/gm;
2652         s/\xc2\x59/Ý/gm;
2653         s/\xc2\x61/á/gm;
2654         s/\xc2\x65/é/gm;
2655         s/\xc2\x69/í/gm;
2656         s/\xc2\x6f/ó/gm;
2657         s/\xc2\x75/ú/gm;
2658         s/\xc2\x79/ý/gm;
2659         s/\xc3\x41/Â/gm;
2660         s/\xc3\x45/Ê/gm;
2661         s/\xc3\x49/Î/gm;
2662         s/\xc3\x4f/Ô/gm;
2663         s/\xc3\x55/Û/gm;
2664         s/\xc3\x61/â/gm;
2665         s/\xc3\x65/ê/gm;
2666         s/\xc3\x69/î/gm;
2667         s/\xc3\x6f/ô/gm;
2668         s/\xc3\x75/û/gm;
2669         s/\xc4\x41/Ã/gm;
2670         s/\xc4\x4e/Ñ/gm;
2671         s/\xc4\x4f/Õ/gm;
2672         s/\xc4\x61/ã/gm;
2673         s/\xc4\x6e/ñ/gm;
2674         s/\xc4\x6f/õ/gm;
2675         s/\xc8\x41/Ä/gm;
2676         s/\xc8\x45/Ë/gm;
2677         s/\xc8\x49/Ï/gm;
2678         s/\xc8\x61/ä/gm;
2679         s/\xc8\x65/ë/gm;
2680         s/\xc8\x69/ï/gm;
2681         s/\xc8\x6F/ö/gm;
2682         s/\xc8\x75/ü/gm;
2683         s/\xc8\x76/ÿ/gm;
2684         s/\xc9\x41/Ä/gm;
2685         s/\xc9\x45/Ë/gm;
2686         s/\xc9\x49/Ï/gm;
2687         s/\xc9\x4f/Ö/gm;
2688         s/\xc9\x55/Ü/gm;
2689         s/\xc9\x61/ä/gm;
2690         s/\xc9\x6f/ö/gm;
2691         s/\xc9\x75/ü/gm;
2692         s/\xca\x41/Å/gm;
2693         s/\xca\x61/å/gm;
2694         s/\xd0\x43/Ç/gm;
2695         s/\xd0\x63/ç/gm;
2696
2697         # this handles non-sorting blocks (if implementation requires this)
2698         $string = nsb_clean($_);
2699     }
2700     elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2701         if (/[\xc1-\xff]/) {
2702             s/\xe1\x61/à/gm;
2703             s/\xe1\x65/è/gm;
2704             s/\xe1\x69/ì/gm;
2705             s/\xe1\x6f/ò/gm;
2706             s/\xe1\x75/ù/gm;
2707             s/\xe1\x41/À/gm;
2708             s/\xe1\x45/È/gm;
2709             s/\xe1\x49/Ì/gm;
2710             s/\xe1\x4f/Ò/gm;
2711             s/\xe1\x55/Ù/gm;
2712             s/\xe2\x41/Á/gm;
2713             s/\xe2\x45/É/gm;
2714             s/\xe2\x49/Í/gm;
2715             s/\xe2\x4f/Ó/gm;
2716             s/\xe2\x55/Ú/gm;
2717             s/\xe2\x59/Ý/gm;
2718             s/\xe2\x61/á/gm;
2719             s/\xe2\x65/é/gm;
2720             s/\xe2\x69/í/gm;
2721             s/\xe2\x6f/ó/gm;
2722             s/\xe2\x75/ú/gm;
2723             s/\xe2\x79/ý/gm;
2724             s/\xe3\x41/Â/gm;
2725             s/\xe3\x45/Ê/gm;
2726             s/\xe3\x49/Î/gm;
2727             s/\xe3\x4f/Ô/gm;
2728             s/\xe3\x55/Û/gm;
2729             s/\xe3\x61/â/gm;
2730             s/\xe3\x65/ê/gm;
2731             s/\xe3\x69/î/gm;
2732             s/\xe3\x6f/ô/gm;
2733             s/\xe3\x75/û/gm;
2734             s/\xe4\x41/Ã/gm;
2735             s/\xe4\x4e/Ñ/gm;
2736             s/\xe4\x4f/Õ/gm;
2737             s/\xe4\x61/ã/gm;
2738             s/\xe4\x6e/ñ/gm;
2739             s/\xe4\x6f/õ/gm;
2740             s/\xe8\x45/Ë/gm;
2741             s/\xe8\x49/Ï/gm;
2742             s/\xe8\x65/ë/gm;
2743             s/\xe8\x69/ï/gm;
2744             s/\xe8\x76/ÿ/gm;
2745             s/\xe9\x41/Ä/gm;
2746             s/\xe9\x4f/Ö/gm;
2747             s/\xe9\x55/Ü/gm;
2748             s/\xe9\x61/ä/gm;
2749             s/\xe9\x6f/ö/gm;
2750             s/\xe9\x75/ü/gm;
2751             s/\xea\x41/Å/gm;
2752             s/\xea\x61/å/gm;
2753
2754             # this handles non-sorting blocks (if implementation requires this)
2755             $string = nsb_clean($_);
2756         }
2757     }
2758     return ($string);
2759 }
2760
2761 sub nsb_clean {
2762     my $NSB = '\x88';    # NSB : begin Non Sorting Block
2763     my $NSE = '\x89';    # NSE : Non Sorting Block end
2764                          # handles non sorting blocks
2765     my ($string) = @_;
2766     $_ = $string;
2767     s/$NSB/(/gm;
2768     s/[ ]{0,1}$NSE/) /gm;
2769     $string = $_;
2770     return ($string);
2771 }
2772
2773 sub FindDuplicate {
2774         my ($record)=@_;
2775         my $dbh = C4::Context->dbh;
2776         my $result = MARCmarc2koha($dbh,$record,'');
2777         my $sth;
2778         my ($biblionumber,$bibid,$title);
2779         # search duplicate on ISBN, easy and fast...
2780         if ($result->{isbn}) {
2781                 $sth = $dbh->prepare("select biblio.biblionumber,bibid,title from biblio,biblioitems,marc_biblio where biblio.biblionumber=biblioitems.biblionumber and marc_biblio.biblionumber=biblioitems.biblionumber and isbn=?");
2782                 $sth->execute($result->{'isbn'});
2783                 ($biblionumber,$bibid,$title) = $sth->fetchrow;
2784                 return $biblionumber,$bibid,$title if ($biblionumber);
2785         }
2786         # a more complex search : build a request for SearchMarc::catalogsearch()
2787         my (@tags, @and_or, @excluding, @operator, @value, $offset,$length);
2788         # search on biblio.title
2789         my ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.title","");
2790         if ($record->field($tag)) {
2791                 if ($record->field($tag)->subfields($subfield)) {
2792                         push @tags, "'".$tag.$subfield."'";
2793                         push @and_or, "and";
2794                         push @excluding, "";
2795                         push @operator, "contains";
2796                         push @value, $record->field($tag)->subfield($subfield);
2797 #                       warn "for title, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2798                 }
2799         }
2800         # ... and on biblio.author
2801         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.author","");
2802         if ($record->field($tag)) {
2803                 if ($record->field($tag)->subfields($subfield)) {
2804                         push @tags, "'".$tag.$subfield."'";
2805                         push @and_or, "and";
2806                         push @excluding, "";
2807                         push @operator, "contains";
2808                         push @value, $record->field($tag)->subfield($subfield);
2809 #                       warn "for author, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2810                 }
2811         }
2812         # ... and on publicationyear.
2813         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publicationyear","");
2814         if ($record->field($tag)) {
2815                 if ($record->field($tag)->subfields($subfield)) {
2816                         push @tags, "'".$tag.$subfield."'";
2817                         push @and_or, "and";
2818                         push @excluding, "";
2819                         push @operator, "=";
2820                         push @value, $record->field($tag)->subfield($subfield);
2821 #                       warn "for publicationyear, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2822                 }
2823         }
2824         # ... and on size.
2825         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.size","");
2826         if ($record->field($tag)) {
2827                 if ($record->field($tag)->subfields($subfield)) {
2828                         push @tags, "'".$tag.$subfield."'";
2829                         push @and_or, "and";
2830                         push @excluding, "";
2831                         push @operator, "=";
2832                         push @value, $record->field($tag)->subfield($subfield);
2833 #                       warn "for size, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2834                 }
2835         }
2836         # ... and on publisher.
2837         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publishercode","");
2838         if ($record->field($tag)) {
2839                 if ($record->field($tag)->subfields($subfield)) {
2840                         push @tags, "'".$tag.$subfield."'";
2841                         push @and_or, "and";
2842                         push @excluding, "";
2843                         push @operator, "=";
2844                         push @value, $record->field($tag)->subfield($subfield);
2845 #                       warn "for publishercode, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2846                 }
2847         }
2848         # ... and on volume.
2849         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.volume","");
2850         if ($record->field($tag)) {
2851                 if ($record->field($tag)->subfields($subfield)) {
2852                         push @tags, "'".$tag.$subfield."'";
2853                         push @and_or, "and";
2854                         push @excluding, "";
2855                         push @operator, "=";
2856                         push @value, $record->field($tag)->subfield($subfield);
2857 #                       warn "for volume, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2858                 }
2859         }
2860
2861         my ($finalresult,$nbresult) = C4::SearchMarc::catalogsearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10);
2862         # there is at least 1 result => return the 1st one
2863         if ($nbresult) {
2864 #               warn "$nbresult => ".@$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
2865                 return @$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
2866         }
2867         # no result, returns nothing
2868         return;
2869 }
2870
2871 sub DisplayISBN {
2872         my ($isbn)=@_;
2873         my $seg1;
2874         if(substr($isbn, 0, 1) <=7) {
2875                 $seg1 = substr($isbn, 0, 1);
2876         } elsif(substr($isbn, 0, 2) <= 94) {
2877                 $seg1 = substr($isbn, 0, 2);
2878         } elsif(substr($isbn, 0, 3) <= 995) {
2879                 $seg1 = substr($isbn, 0, 3);
2880         } elsif(substr($isbn, 0, 4) <= 9989) {
2881                 $seg1 = substr($isbn, 0, 4);
2882         } else {
2883                 $seg1 = substr($isbn, 0, 5);
2884         }
2885         my $x = substr($isbn, length($seg1));
2886         my $seg2;
2887         if(substr($x, 0, 2) <= 19) {
2888 #               if(sTmp2 < 10) sTmp2 = "0" sTmp2;
2889                 $seg2 = substr($x, 0, 2);
2890         } elsif(substr($x, 0, 3) <= 699) {
2891                 $seg2 = substr($x, 0, 3);
2892         } elsif(substr($x, 0, 4) <= 8399) {
2893                 $seg2 = substr($x, 0, 4);
2894         } elsif(substr($x, 0, 5) <= 89999) {
2895                 $seg2 = substr($x, 0, 5);
2896         } elsif(substr($x, 0, 6) <= 9499999) {
2897                 $seg2 = substr($x, 0, 6);
2898         } else {
2899                 $seg2 = substr($x, 0, 7);
2900         }
2901         my $seg3=substr($x,length($seg2));
2902         $seg3=substr($seg3,0,length($seg3)-1) ;
2903         my $seg4 = substr($x, -1, 1);
2904         return "$seg1-$seg2-$seg3-$seg4";
2905 }
2906
2907
2908 END { }    # module clean-up code here (global destructor)
2909
2910 =back
2911
2912 =head1 AUTHOR
2913
2914 Koha Developement team <info@koha.org>
2915
2916 Paul POULAIN paul.poulain@free.fr
2917
2918 =cut
2919
2920 # $Id$
2921 # $Log$
2922 # Revision 1.138  2006/02/14 11:25:22  tipaul
2923 # road to 3.0 : updating a biblio in zebra seems to work. Still working on it, there are probably some bugs !
2924 #
2925 # Revision 1.137  2006/02/13 16:34:26  tipaul
2926 # fixing some warnings (perl -w should be quiet)
2927 #
2928 # Revision 1.136  2006/01/10 17:01:29  tipaul
2929 # adding a XMLgetbiblio in Biblio.pm (1st draft, to use with zebra)
2930 #
2931 # Revision 1.135  2006/01/06 16:39:37  tipaul
2932 # synch'ing head and rel_2_2 (from 2.2.5, including npl templates)
2933 # Seems not to break too many things, but i'm probably wrong here.
2934 # at least, new features/bugfixes from 2.2.5 are here (tested on some features on my head local copy)
2935 #
2936 # - removing useless directories (koha-html and koha-plucene)
2937 #
2938 # Revision 1.134  2006/01/04 15:54:55  tipaul
2939 # utf8 is a : go for beta test in HEAD.
2940 # some explanations :
2941 # - updater/updatedatabase => will transform all tables in innoDB (not related to utf8, just to warn you) AND collate them in utf8 / utf8_general_ci. The SQL command is : ALTER TABLE tablename DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci.
2942 # - *-top.inc will show the pages in utf8
2943 # - THE HARD THING : for me, mysql-client and mysql-server were set up to communicate in iso8859-1, whatever the mysql collation ! Thus, pages were improperly shown, as datas were transmitted in iso8859-1 format ! After a full day of investigation, someone on usenet pointed "set NAMES 'utf8'" to explain that I wanted utf8. I could put this in my.cnf, but if I do that, ALL databases will "speak" in utf8, that's not what we want. Thus, I added a line in Context.pm : everytime a DB handle is opened, the communication is set to utf8.
2944 # - using marcxml field and no more the iso2709 raw marc biblioitems.marc field.
2945 #
2946 # Revision 1.133  2005/12/12 14:25:51  thd
2947 #
2948 #
2949 # Reverse array filled with elements from repeated subfields
2950 # to avoid last to first concatenation of elements in Koha DB.-
2951 #
2952 # Revision 1.132  2005-10-26 09:12:33  tipaul
2953 # big commit, still breaking things...
2954 #
2955 # * synch with rel_2_2. Probably the last non manual synch, as rel_2_2 should not be modified deeply.
2956 # * code cleaning (cleaning warnings from perl -w) continued
2957 #
2958 # Revision 1.131  2005/09/22 10:01:45  tipaul
2959 # see mail on koha-devel : code cleaning on Search.pm + normalizing API + use of biblionumber everywhere (instead of bn, biblio, ...)
2960 #
2961 # Revision 1.130  2005/09/02 14:34:14  tipaul
2962 # continuing the work to move to zebra. Begin of work for MARC=OFF support.
2963 # IMPORTANT NOTE : the MARCkoha2marc sub API has been modified. Instead of biblionumber & biblioitemnumber, it now gets a hash.
2964 # The sub is used only in Biblio.pm, so the API change should be harmless (except for me, but i'm aware ;-) )
2965 #
2966 # Revision 1.129  2005/08/12 13:50:31  tipaul
2967 # removing useless sub declarations
2968 #
2969 # Revision 1.128  2005/08/11 16:12:47  tipaul
2970 # Playing with the zebra...
2971 #
2972 # * go to koha cvs home directory
2973 # * in misc/zebra there is a unimarc directory. I suggest that marc21 libraries create a marc21 directory
2974 # * put your zebra.cfg files here & create your database.
2975 # * from koha cvs home directory, ln -s misc/zebra/marc21 zebra (I mean create a symbolic link to YOUR zebra directory)
2976 # * now, everytime you add/modify a biblio/item your zebra DB is updated correctly.
2977 #
2978 # NOTE :
2979 # * this uses a system call in perl. CPU consumming, but we are waiting for indexdata Perl/zoom
2980 # * deletion still not work
2981 # * UNIMARC zebra config files are provided in misc/zebra/unimarc directory. The most important line being :
2982 # in zebra.cfg :
2983 # recordId: (bib1,Local-number)
2984 # storeKeys:1
2985 #
2986 # in .abs file :
2987 # elm 090            Local-number            -
2988 # elm 090/?          Local-number            -
2989 # elm 090/?/9        Local-number            !:w
2990 #
2991 # (090$9 being the field mapped to biblio.biblionumber in Koha)
2992 #
2993 # Revision 1.127  2005/08/11 14:37:32  tipaul
2994 # * POD documenting
2995 # * removing useless subs
2996 # * removing some subs that are also elsewhere
2997 # * renaming all OLDxxx subs to REALxxx subs (should not change anything, as OLDxxx, as well as REAL, are supposed to be for Biblio.pm internal use only)
2998 #
2999 # Revision 1.126  2005/08/11 09:13:28  tipaul
3000 # just removing useless subs (a lot !!!) for code cleaning
3001 #
3002 # Revision 1.125  2005/08/11 09:00:07  tipaul
3003 # Ok guys, this time, it seems that item add and modif begin working as expected...
3004 # Still a lot of bugs to fix, of course
3005 #
3006 # Revision 1.124  2005/08/10 10:21:15  tipaul
3007 # continuing the road to zebra :
3008 # - the biblio add begins to work.
3009 # - the biblio modif begins to work.
3010 #
3011 # (still without doing anything on zebra)
3012 # (no new change in updatedatabase)
3013 #
3014 # Revision 1.123  2005/08/09 14:10:28  tipaul
3015 # 1st commit to go to zebra.
3016 # don't update your cvs if you want to have a working head...
3017 #
3018 # this commit contains :
3019 # * updater/updatedatabase : get rid with marc_* tables, but DON'T remove them. As a lot of things uses them, it would not be a good idea for instance to drop them. If you really want to play, you can rename them to test head without them but being still able to reintroduce them...
3020 # * Biblio.pm : modify MARCgetbiblio to find the raw marc record in biblioitems.marc field, not from marc_subfield_table, modify MARCfindframeworkcode to find frameworkcode in biblio.frameworkcode, modify some other subs to use biblio.biblionumber & get rid of bibid.
3021 # * other files : get rid of bibid and use biblionumber instead.
3022 #
3023 # What is broken :
3024 # * does not do anything on zebra yet.
3025 # * if you rename marc_subfield_table, you can't search anymore.
3026 # * you can view a biblio & bibliodetails, go to MARC editor, but NOT save any modif.
3027 # * don't try to add a biblio, it would add data poorly... (don't try to delete either, it may work, but that would be a surprise ;-) )
3028 #
3029 # IMPORTANT NOTE : you need MARC::XML package (http://search.cpan.org/~esummers/MARC-XML-0.7/lib/MARC/File/XML.pm), that requires a recent version of MARC::Record
3030 # Updatedatabase stores the iso2709 data in biblioitems.marc field & an xml version in biblioitems.marcxml Not sure we will keep it when releasing the stable version, but I think it's a good idea to have something readable in sql, at least for development stage.
3031
3032 # tipaul cutted previous commit notes