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